Functional programming writer单子和list writer单子的区别是什么

Functional programming writer单子和list writer单子的区别是什么,functional-programming,monads,Functional Programming,Monads,我通过查看writer monad的示例来了解它是如何工作的,几乎所有这些示例都像是列表编写器monad。我知道列表编写器monad是编写器monad的一种类型。但在外行术语中,writer monad的真正含义是什么呢?在外行术语中,writer monad是在生成值时允许您将项目“写入”到“日志”的monad。完成后,您将得到生成的值和包含您编写的所有内容的日志。换句话说,单子的副作用是“把东西写进日志” 让我们通过列表编写器和(通用)编写器monad的示例来更具体地说明这一点。我将在这里使

我通过查看writer monad的示例来了解它是如何工作的,几乎所有这些示例都像是列表编写器monad。我知道列表编写器monad是编写器monad的一种类型。但在外行术语中,writer monad的真正含义是什么呢?

在外行术语中,writer monad是在生成值时允许您将项目“写入”到“日志”的monad。完成后,您将得到生成的值和包含您编写的所有内容的日志。换句话说,单子的副作用是“把东西写进日志”

让我们通过列表编写器和(通用)编写器monad的示例来更具体地说明这一点。我将在这里使用Haskell,因为它是我们描述的原始上下文

单子 我假设“列表编写器”monad将一个项目(我们称之为
w
)记录到一个项目列表(当然是
[w]
)中。它还生成类型为
a
的值。(如果您自己使用此代码遇到错误,请参阅底部的注释。)

(注意:这相当于
ex1=tell“foo”>>tell“bar”>>返回0
,演示如何使用
tell
>
将项目添加到日志中。)

如果我们在GHCi中评估
runListWriter ex1
,我们会看到它将“foo”和“bar”写入日志,并生成结果值
0

λ> runListWriter ex1
(["foo","bar"],0)
(通用)编写器Monad 现在,让我们看看如何将其转换为通用编写器monad。作者monad处理任何可以组合在一起的东西,而不仅仅是列表。具体来说,它与任何
幺半群一起工作:

class Monoid m where
  mempty :: m            -- an empty m
  mappend :: m -> m -> m -- combine two m's into a single m
列表是一个幺半群,分别具有
[]
(++)
作为
mempty
mappend
。幺半群的一个非列表示例是整数和:

λ> Sum 1 <> Sum 2        -- (<>) = mappend
Sum {getSum = 3}
我们没有列出
w
,只有一个w。但是当我们定义Monad时,我们确保
w
Monoid
,因此我们可以从一个空日志开始,并在日志中附加一个新条目:

instance Monoid w => Monad (Writer w) where
  return a = Writer (mempty, a)   -- produce an a, don't log anything
  Writer (w, a) >>= k =
    let Writer (x, a') = k a      -- we combine the two w's rather than 
    in Writer (w <> x, a')        -- (++)-ing two lists
ex2 :: Writer [String] Int
ex2 = do
  tell ["foo"]
  tell ["bar"]
  return 0
但你会得到同样的结果:

λ>  runWriter ex2
(["foo","bar"],0)
这是因为您没有记录“将放入列表的项目”,而是记录“列表”。(这意味着您可以通过传递多个元素的列表同时记录多个项目。)

对于一个非列表使用的作者,考虑计算排序函数所做的比较。每次函数进行比较时,都可以

告诉(Sum 1)
。(你可以告诉别人。明白了吗?这个东西打开了吗?)然后,在最后,你会得到所有比较的总计数(即总和)以及排序列表


注意:如果您尝试自己使用这些
ListWriter
Writer
定义,GHC将告诉您缺少
Functor
Applicative
实例。一旦拥有了
Monad
实例,就可以用它的术语编写其他实例:

import Control.Monad (ap, liftM)

instance Functor (ListWriter w) where
  fmap = liftM

instance Applicative (ListWriter w) where
  pure = return
  (<*>) = ap
import Control.Monad(ap,liftM)
实例函子(ListWriter w),其中
fmap=liftM
实例应用程序(ListWriter w),其中
纯=返回
()=ap

对于
Writer
,也是如此。为了清晰起见,我在上面省略了它们。

请添加相关语言。任何语言都可以,因为我更多地关注的是它的概念,而不是实现。您能否引用“列表编写器monad”的参考资料。
λ>  runWriter ex2
(["foo","bar"],0)
import Control.Monad (ap, liftM)

instance Functor (ListWriter w) where
  fmap = liftM

instance Applicative (ListWriter w) where
  pure = return
  (<*>) = ap