簡體   English   中英

使Writer(Haskell)成為Monoid實例

[英]Make Monoid instance of Writer (Haskell)

在Haskell中,我想將Writer monad設為一個monoid的實例:

instance (Monoid a) => Monoid (Writer (Sum Int) a) where
  mempty = return mempty
  w1 `mappend` w2 = writer((s++t, s'++t'), Sum (m+n)) where
    ((s,s'), Sum m) = runWriter w1
    ((t,t'), Sum n) = runWriter w2

因此,直觀地講,如果Writer monad的“數據”類型是一個monoid,那么我也希望能夠將整個Writer事物視為一個monoid(由mem​​pty和mappend實現)。

但是,這不起作用:GHCI編譯器說

Illegal instance declaration for `Monoid (Writer (Sum Int) a)'
  (All instance types must be of the form (T t1 ... tn)
   where T is not a synonym.
   Use -XTypeSynonymInstances if you want to disable this.)
In the instance declaration for `Monoid (Writer (Sum Int) a)'

而且我真的不知道在這里什么類型應該是同義詞,以及我如何才能符合編譯器的規則。

每個人都在做很多工作。 writer monad上的bind運算符已經附加了w s。 這也意味着它將適用於任意基本monad。

instance (Monoid w, Monoid a, Monad m) => Monoid (WriterT w m a) where
    mempty = return mempty
    mappend = liftA2 mappend

在這一點上,很明顯,甚至WriterT都是多余的,這實際上是這個通用instance的“實例”

instance (Monoid a, Monad m) => Monoid (m a) where
    -- same

但是Haskell的類系統實際上並不允許這樣的實例-它會匹配從類型構造函數構建的每個monoid。 例如,此實例將匹配Sum Int ,然后失敗,因為Sum不是monad。 因此,您必須針對您感興趣的每個單子分別指定它。

Writer是類型別名(鏈接)

type Writer w = WriterT w Identity

因此請改用WriterT ... Identity 您仍然需要啟用FlexibleInstances。

也許這就是您所追求的:

{-# LANGUAGE FlexibleInstances #-}

import Control.Monad.Trans.Writer
import Data.Monoid
import Data.Functor.Identity

instance (Monoid w, Monoid a) => Monoid (WriterT w Identity a) where
  mempty = return mempty
  m1 `mappend` m2 = writer (a1 <> a2, w1 <> w2)
    where
      (a1,w1) = runWriter m1
      (a2,w2) = runWriter m2

當然,可以將其推廣到任意Monad而不是Identity。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM