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
值,其中将一系列状态计算绑定在一起应该会导致每个人“看到”状态