Haskell 为什么state和reader monad是函数,而writer monad是元组?

Haskell 为什么state和reader monad是函数,而writer monad是元组?,haskell,state,monads,functor,Haskell,State,Monads,Functor,我是哈斯克尔的新手,我想我了解单子和它们的机制(至少对于单子的列表、状态、可能的作者和读者来说),但我想了解为什么它们被定义为这样,或者为什么它们必须是这样,以帮助我的直觉思考它们 具体来说,是什么让读卡器或状态单子需要是函数(即\s->(a,s)),而不仅仅是像writer单子那样的数据(即(w,a)) 另外,只要不使用MonadPlus功能,writer monad是否可以用作状态monad,其中日志被用作状态的字符串表示?与writer monad一起使用的monadic函数是否允许查看当

我是哈斯克尔的新手,我想我了解单子和它们的机制(至少对于单子的列表、状态、可能的作者和读者来说),但我想了解为什么它们被定义为这样,或者为什么它们必须是这样,以帮助我的直觉思考它们

具体来说,是什么让读卡器或状态单子需要是函数(即
\s->(a,s)
),而不仅仅是像writer单子那样的数据(即
(w,a)

另外,只要不使用
MonadPlus
功能,writer monad是否可以用作状态monad,其中日志被用作状态的字符串表示?与writer monad一起使用的monadic函数是否允许查看当前日志并随意修改,还是仅允许writer monad的bind函数查看日志

还有,为什么单子是用类型为
a->mb
的单子函数定义的,而不是用类型为
ma->mb
的单子函数定义的?函数从基类型变为单子包装类型有什么自然之处


感谢您的回答。

状态和阅读器monad都取决于我们感兴趣的任何状态的值。 我们需要能够访问它,否则我们怎么能写这样的东西呢

foo = do
 i <- get
 return $ if i == 1 then 2 else 3
foo=do
i(s,a)
哪一个是状态单子:)是的,无论你能用状态单子做什么,都可以用这个扩展的编写器来完成

事实上,
StateT
WriterT
monad都有
MonadPlus
实例,所以我不确定这里的内容

  • 由于没有任意函数
    ma->a
    ,我们需要某种方法来展开计算以查看结果,并且由于
    return::a->ma
    使换一种方法变得很简单,因此从普通值到一元值更为普遍。否则我们只会有这些无用的
    IO字符串
    STM Int
    以及其他我们在剩下的计算中无法依赖的东西,因为
    fmap
    不会让我们产生更多的副作用

  • 具体来说,是什么让读卡器或状态单子需要是函数(即
    \s->(a,s)
    ),而不仅仅是像writer单子那样的数据(即
    (w,a)

    函数只是数据。这些恰好是最适合所需语义的类型

    另外,只要不使用MonadPlus功能,writer monad是否可以用作状态monad,其中日志被用作状态的字符串表示

    您无法传递非空的初始状态,并且只能通过附加值来修改它。如果您确实更改了这一点,您将获得标准状态monad(仅字符串除外)

    与writer monad一起使用的monadic函数是否允许查看当前日志并随意修改,还是仅允许writer monad的bind函数查看日志

    您会注意到Writer monad有一个
    tell
    函数,它实际上向日志中添加了新数据

    还有,为什么单子是用类型
    a->mb
    的单子函数定义的,而不是用类型
    ma->mb
    ?函数从基类型变为单子包装类型有什么自然之处


    我认为最好的答案是“因为
    a->mb
    更有用”

    它们的定义不同,因为它们做的事情不同

    以读者monad为例。首先思考它的含义,而不是它是如何工作的

    读卡器monad中的计算依赖于一条额外的信息,即读卡器的“环境”。因此,
    Reader Env Int
    是一个依赖于环境的
    Int
    (类型为
    Env
    );如果我用一个环境评估它,我会得到一个
    Int
    值,如果我用另一个环境评估它,我会得到另一个
    Int
    值。如果我没有环境,我就不知道
    Reader env Int
    的值是多少

    现在,如果我给它一个
    Env
    ,什么样的值会给我一个
    Int
    ?类型为
    Env->Int
    的函数!因此,这概括为
    e->a
    是每个
    e
    的单子(其中
    a
    是单子的类型参数;
    (>)e
    ,如果您喜欢前缀符号)

    现在让我们思考一下作者monad的意思。writer monad中的计算产生一个值,但它也产生一个额外的“边”值:“log”值。当我们将writer monad中的一系列一元计算绑定在一起时,日志值将被合并(如果我们要求日志类型为monoid,那么这保证了日志值可以在不知道它们是什么的情况下合并)。因此,
    Writer Log Int
    是一个
    Int
    类型的值

    这听起来很像一对:
    (Log,Int)
    。这概括为
    (w,a)
    是每个
    w
    的单子(其中
    a
    是单子的类型参数)。
    w
    上的monoid约束保证我们可以组合日志值,这也意味着我们有一个明显的起始值(monoid的标识元素:
    mempty
    ),因此我们不需要提供任何东西来从writer monad中的值中获取值

    将状态monad设置为
    s->(a,s)
    的推理实际上几乎是上述的组合;
    State S Int
    是一个
    Int
    ,它既取决于
    S
    值(因为读取器取决于环境),又产生一个
    S
    值,其中将一系列状态计算绑定在一起应该会导致每个人“看到”状态