生成编写器的幺半群实例(Haskell)

生成编写器的幺半群实例(Haskell),haskell,functional-programming,Haskell,Functional Programming,在Haskell中,我想将Writer monad作为幺半群的一个实例: 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 w

在Haskell中,我想将Writer monad作为幺半群的一个实例:

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
[P> >直观地说,如果作者Maad的“数据”类型是幺半群,那么我希望能够将整个作者的事物看作一个幺半群(由MimpTy和MappEnter实现)。 不过,这是行不通的: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
是一个类型别名

因此,请改用
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.Trans.Writer
导入数据.幺半群
导入Data.Functor.Identity
实例(幺半群w,幺半群a)=>幺半群(WriterT w Identity a),其中
mempty=返回mempty
m1`mappend`m2=写入程序(a1 a2,w1 w2)
哪里
(a1,w1)=运行写入程序m1
(a2,w2)=平方米

当然,这可以推广到任意单子而不是标识。

Writer
是一个类型别名

因此,请改用
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.Trans.Writer
导入数据.幺半群
导入Data.Functor.Identity
实例(幺半群w,幺半群a)=>幺半群(WriterT w Identity a),其中
mempty=返回mempty
m1`mappend`m2=写入程序(a1 a2,w1 w2)
哪里
(a1,w1)=运行写入程序m1
(a2,w2)=平方米

当然,这可以推广到任意单子而不是标识。

每个人都在做大量的工作。writer单子上的bind操作符已经附加了
w
s。这也意味着它将适用于任意基单子

instance (Monoid w, Monoid a, Monad m) => Monoid (WriterT w m a) where
    mempty = return mempty
    mappend = liftA2 mappend
在这一点上,很明显,即使是
WriterT
也是多余的,而这实际上是这个一般
实例的一个“实例”

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

但是Haskell的类系统实际上不允许这样的实例——它将匹配从类型构造函数构建的每个幺半群。例如,这个实例将匹配
Sum Int
,然后失败,因为
Sum
不是单子。所以你必须为你感兴趣的每个单子分别指定它。

每个人都在这样做工作量太大了。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 (Monoid a, Monad m) => Monoid (m a) where
    -- same

但是Haskell的类系统实际上不允许这样的实例——它将匹配从类型构造函数构建的每个幺半群。例如,此实例将匹配
Sum Int
,然后失败,因为
Sum
不是单子。因此,您必须为感兴趣的每个单子分别指定它。

不符合规则:按照编译器的建议,通过启用
-XTypeSynonymInstances
来释放它们。
-xflexibleInstances
也可能是必需的。不符合规则:按照编译器的建议,通过启用
-XTypeSynonymInstances
来释放它们。
-xflexibleInstances
也可能是必需的。我认为扩展可以是avo我想更一般地处理
WriterT
。我认为扩展可以通过更一般地处理
WriterT
来避免。肯定有一个扩展可以做到这一点,不是吗?太尴尬了!毕竟,我是建议将
Ap
添加到
数据中的人。Monoid
,使用
新类型Ap f a=Ap(f a)
实例(应用程序f,幺半群a)=>幺半群(Ap f a)
。请注意,
Monad
太过分了。@Bergi,有重叠的实例,但它们是邪恶的。肯定有这样的扩展,不是吗?太尴尬了!毕竟,我是建议将
Ap
添加到
数据中的人。Monoid
,带有
newtype Ap f a=Ap(f a)
实例(Applicative f,Monoid a)=>Monoid(Ap f a)
。请注意,
Monad
太过分了。@Bergi,有重叠的实例,但它们是邪恶的。