首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何设计一个一元堆栈?

如何设计一个一元堆栈?
EN

Stack Overflow用户
提问于 2013-05-09 07:57:46
回答 2查看 1.2K关注 0票数 28

如何设计和构建您的一元堆栈?这是我第一次需要构建一个一元堆栈(使用变压器)来解决现实世界的问题,但我并不完全确定变压器的堆叠顺序。正如您已经知道的,只要计算有类* -> *,基本上任何东西都可以在变压器中扮演内部单体的角色,因此有以下几个问题:

  • 某个特定的转换器是否应该位于堆栈的顶部(例如,ReaderT )?WriterT?)
  • 设计的动力应该是什么?直觉?类型?(例如,根据API的需要构造堆栈)
  • 每个堆栈是否都是同构的(在某种程度上),还是说,如果我构建的堆栈不正确,我最终可能无法使用某些底层的单元组,或者lift . lift . liftIO [...]会变得臃肿不堪?我的直觉表明,如果变压器得到某些实例(例如,MonadReader、MonadIO等,就像mtl中的大多数变压器一样),那么我放置变压器的顺序应该无关紧要。

我有兴趣从经验丰富的Haskellers那里了解最佳实践或经验规则。

forever $ print "Thanks!"

一个。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2013-05-10 15:06:27

这需要经验。需要记住的一点是,单体变压器对它正在转变的单体一无所知,因此外部变压器被内部行为“束缚”。所以

代码语言:javascript
复制
StateT s (ListT m) a

首先,也是最重要的,由于内部的单元化,它是一种不确定的计算。然后,以非决定论为标准,添加状态--也就是说,非决定论的每个“分支”都有自己的状态。

ListT (StateT s m) a进行对比,它主要是有状态的--也就是说,整个计算只有一个状态(模块化m),并且计算将在状态中充当“单线程”,因为这就是State的意思。不确定性将在此之上--这样,分支就能够观察到以前失败的分支的状态变化。(在这个特殊的组合中,这真的很奇怪,而且我从来不需要它)。

下面是Dan的一个图解,它给出了一些有用的直觉:

我还发现将其扩展到实现类型是有帮助的,可以让我对它是什么样的计算有一种感觉。ListT很难扩展,但是您可以看到它是“不确定性”,而StateT很容易扩展。所以对于上面的例子,我想看看

代码语言:javascript
复制
StateT s (ListT m) a =~ s -> ListT m (a,s)

也就是说,它接受一个传入状态,并返回许多传出状态。这给了你一个想法,它将如何运作。类似的方法是查看堆栈所需的run函数的类型--这是否与您所拥有的信息和所需的信息相匹配?

以下是一些经验法则。它们不能代替花时间通过扩展和查找来找出您真正需要的功能,但是如果您只是在寻找某种命令式意义上的“添加功能”,那么这可能是有帮助的。

ReaderTWriterTStateT是最常见的变压器。首先,它们都是相互通勤的,所以您把它们放在什么顺序是无关紧要的(不过,如果您使用这三种方式的话,可以考虑使用RWS )。此外,在实践中,我通常希望这些在外面,“更富有”的变压器,如ListTLogicT,和ContT在里面。

ErrorTMaybeT通常在上述三个方面之外;让我们看看MaybeT如何与StateT交互

代码语言:javascript
复制
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位于内部时,如果计算失败,则不会得到状态,因此必须中止在失败计算中发生的任何状态更改。你想要哪一个取决于你想要做什么--但是前者对应于命令式程序员的直觉。(这并不是一定要争取的)

我希望这能让您了解如何考虑转换器堆栈,因此您有更多的工具来分析您的堆栈应该是什么样子。如果你认为一个问题是一种一元计算,那么得到正确的单点计算是最重要的决定之一,而这并不总是那么容易。慢慢来,探索各种可能性。

票数 28
EN

Stack Overflow用户

发布于 2013-05-09 08:48:58

这是一个相当广泛的问题。我只想给你们一些基本的想法。

首先,我建议尽可能保持基单多态。这将允许您在纯和IO设置中重用代码。这也将使您的代码更加可组合。使用各种类(如MonadIO )也可以帮助保持代码的多态性,这通常是一件好事。

需要注意的一件重要的事情是,您的单台转换器的顺序实际上控制着它们的语义。我最喜欢的示例是将类似于ListT1的内容与用于错误处理的EitherT组合起来。如果外部有ListT,则整个计算可能会出错。如果外部有EitherT,那么每个分支都可以分别失败。所以你可以通过改变变压器的顺序来控制错误与非决定论的交互方式!

如果您使用的单台变压器不依赖于订单。我相信,将ReaderTWriterT结合在一起并不重要--那么就直接播放它,然后使用对您的应用程序最合适的东西。这是一种经验比较容易的选择。

来自ListTControl.Monad.Trans有一些问题,所以假设它是做得对

票数 12
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/16457111

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档