繁体   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