MaybeT
monad 转换器:
newtype MaybeT m a = MaybeT { runMaybeT :: m (Maybe a) }
我没想到它会有不同的定义,因为
Maybe
只是一种带有(可选)内容的盒子(上面的类型 a
),所以 MaybeT
可以用参数做什么m
,如果不把整个Maybe
包裹在里面呢?写 :: Maybe (m a)
是没有意义的,因为这只是 someaction <$> theMaybe
的类型。
但在其他情况下,可能还有其他选择。
StateT
monad 转换器,定义为
newtype StateT s m a = StateT { runStateT :: s -> m (a, s) }
这个定义,如果我根据
State
monad 的定义来看待它(显然,如果它没有通过 StateT
在 Identity
之上定义),
newtype State s a = State { runState :: s -> (a, s) }
似乎符合“一个函数
a -> b
作为一个包含内容b
的容器”的解释,这就是我最初理解Functor
的(->) r
实例的含义是什么。公平地说,m
正在包装函数的“内容”(即状态计算的“内容”)。
但这(或者在我看来!)与
MaybeT
的情况完全不同,其中 m
并不包裹 Maybe
的内部,即 a
,而是整个 Maybe a
。
如果
StateT
必须类似于 MaybeT
(实际上使用 m
来包裹整个东西),它就会像这样
newtype StateT' s m a = StateT' { runStateT' :: m (s -> (a,s)) }
想到这里,我想到了一些想法:
IO
之上运行这样的 monad 转换器意味着人们可以从s -> (a, s)
monad,而如果实际的 IO
堆叠在 StateT
之上,则 IO
只能用于获取新的 IO
tate 和结果 s
;但我仍然不确定我是否完全理解其中的区别。
a
这感觉有点没用,因为...感觉状态计算没有意义,因为,再次以
newtype StateT'' s m a = StateT'' { runStateT'' :: s -> (m a,s) }
为
m
为例,IO
将来自 a
,但是...哦,我真的不明白。重点是,我体验过 IO
的实用性,但我并不真正理解为什么
有用,而其他替代方案则不然。或者他们会吗?StateT
并思考哪些效果可以由您的类型表示,哪些效果不能。
m = IO
嗯,这变成了 newtype StateT' s m a = StateT' { runStateT' :: m (s -> (a,s)) }
,因此它会在读取当前
IO (s -> (a,s))
状态以生成新的 s
状态(以及结果
s
)之前执行 IO 效果。
所以,这不能表达“读取当前状态并打印它”的计算。没那么有用。
a
我们得到
newtype StateT'' s m a = StateT'' { runStateT'' :: s -> (m a,s) }
。从中很容易获得一个以纯粹方式计算新状态的函数s -> (IO a,s)
。这意味着IO不能影响新的状态。
因此,这不能表达“要求用户进行键盘输入,并据此更改状态”的计算。也没那么有用。