你如何设计和构建一元栈? 第一次我需要建立一个一元堆栈(使用变压器)来解决现实世界的问题,但我不能完全肯定,其中以堆叠的变压器。 正如你已经知道,只要计算有种* -> *
,基本上什么都可以在变压器发挥内单子的作用,从而几个问题:
- 如果一些特殊的变压器是在堆栈的顶部(如ReaderT?WriterT?)
- 什么应该推动设计? 直觉? 类型? (例如,根据您的API的需求塑造堆栈)
- 是每个堆栈同构于对方(在一定程度上),或者是很可能的是,如果我建立我的堆栈错误我可能最终不能够使用某些底层的单子还是有很大的臃肿混乱
lift . lift . liftIO [...]
lift . lift . liftIO [...]
lift . lift . liftIO [...]
? 我的直觉会建议,如果变压器得到某些情况下(如MonadReader,MonadIO等,像大多数变压器mtl
做的),它不应该顺序重要,我把变压器。
我是从经验丰富的Haskellers的最佳做法或经验法则听力的兴趣。
forever $ print "Thanks!"
一个。
这需要经验。 有一点要记住的是,单子转换并不知道它正在改变着单子任何东西,所以外一个是由内一个人的行为,“绑定”。 所以
StateT s (ListT m) a
是,首先,具有不确定性的计算,因为内单子。 然后,以确定性为正常,你加状态 - 即每个非确定性的“分支”将拥有自己的状态。
与Constrast ListT (StateT sm) a
,这主要是状态-即只会有整个计算(模一个状态m
),并计算将采取行动的状态为“单线程”,因为这是State
机构。 该确定性将是最重要的是 - 所以分支机构将能够观察到之前失败的分支机构的状态变化。 (在这个特殊的组合,这是很奇怪的,我从来没有需要的话)。
这里有一个图丹Piponi这给一些有用的直觉:
我还发现它有助于拓展到实现类型,给我的是什么样的计算的感觉。 ListT
扩展困难,但你可以把它看作“nondeterminsm”,并StateT
易于扩展。 因此,对于上面的例子,我想看看
StateT s (ListT m) a =~ s -> ListT m (a,s)
即它需要一个进入状态,并返回多次传出状态。 这给了你它是如何去工作的想法。 类似的方法是看的类型run
,你将需要为您的堆栈功能-这是否匹配你的信息,你需要的信息?
这里有一些经验法则。 他们采取以找出哪一个你真正通过扩大和寻找所需要的时间没有替代品,但如果你只是寻找一种势在必行意义上的“添加功能”,那么这可能是有益的。
ReaderT
, WriterT
和StateT
是最常见的变压器。 首先,他们都下班彼此,所以这是无关紧要的,你把什么样的顺序它们(考虑使用RWS
如果你使用的所有三个,虽然)。 此外,在实践中,我常常想,这些在外面,与“富”如变压器ListT
, LogicT
和ContT
在里面。
ErrorT
和MaybeT
通常走在以上三个外; 让我们来看看如何MaybeT
与之交互StateT
:
MaybeT (StateT s m) a =~ StateT s m (Maybe a) =~ s -> m (Maybe a, s)
StateT s (MaybeT m) a =~ s -> MaybeT m (a,s) =~ s -> m (Maybe (a,s))
当MaybeT
是在外面,状态变化是观察到即使计算失败。 当MaybeT
在里面,如果计算失败,你没有得到一个状态了,所以你要放弃,在失败的计算发生任何状态变化。 其中哪些你想一个取决于你正在尝试做的 - 前者,但是,对应于势在必行程序员的直觉。 (不,这是必然的东西要争取)
我希望这给了你如何看待变压器堆栈的想法,让你有更多的工具来分析你的筹码应该是什么样子。 如果您发现有问题的为一元计算,得到了单子权是做出最重要的决定之一,它并不总是很容易。 把你的时间和探索的可能性。
这是一个相当宽泛的问题。 我只是想给你一些基本的想法进行工作。
首先,我建议保持基本单子多态尽可能。 这将允许你在既纯洁和IO设置重用代码。 这也将让你的代码更可组合。 使用各种类,如MonadIO
也可以帮助保持你的代码更加多态的,通常是一件好事。
需要注意的一件重要的事情是,你的单子变压器的订单实际控制它们的语义。 我最喜欢的例子是结合像ListT
与¹ EitherT
用于错误处理。 如果你有ListT
在外面, 整个计算可以失败,出现错误。 如果您有EitherT
在外面,然后每个分支可单独失败。 所以,可以真正地改变你的变压器的顺序控制误差与非决定论的互动方式!
如果单子变压器你使用不依赖于顺序-例如,它会没有多大关系的结合ReaderT
和WriterT
,我相信-然后就见机行事,用什么似乎最适合你的应用程序去。 这是哪门子的选择,这将得到与体验更轻松。
¹: ListT
从Control.Monad.Trans
有一些问题,所以以为它ListT
做的权利 。