[英]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.