![](/img/trans.png)
[英]haskell: No instance for (Monoid Int) when use writer monad with haskell platform 2013 2.0.0
[英]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(由mempty和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.