我应该如何组合St monad和State monad(或等效的)?

时间:2014-02-20 20:30:28

标签: arrays haskell mutable monad-transformers state-monad

我正在构建代码以获得理解,实际上是一个Solitaire解算器。 我有一个简单的暴力实现,使用State monad,实际上只是为了证明我可以使用它(它只保留每个移动的计数)。 但是现在我想使用Unboxed Mutable数组来记录被访问的​​板,从而在我到达已经通过另一条路径访问的板位置时快速评估路径。 似乎ST monad不允许我线程隐式状态,但是我必须使用ST(或IO)才能访问Mutable数组。因此,似乎我必须结合两个Monads - State来线程化状态(实际上包括一个Mutable数组),另一个(ST)来获得Mutable数组函数。

  • 这是对的吗?
  • 如果是这样,有没有比Data.Array.ST/Control.Monad.ST/Control.Monad.ST和mtl?
  • 的(规范?)组合更好的选择?
  • 如果我走这条路,那么堆叠ST和State的顺序是否重要?
  • 为了避免使用monad变压器,我应该考虑根据ST或State中的任何一个或两个来推销我自己的单个Monad吗?

2 个答案:

答案 0 :(得分:5)

我不是百分之百确定ST monad是改善像这样的搜索任务的性能的方法。但假设它是......您可以通过将要保留的状态放入STRef来“线程化状态”。你可以这样做而不需要将多个monad混合在一起,这样可以使事情变得更加简单。

如果你想要可变状态,你肯定需要ST或IO monad。 (或STM monad,但这只用于线程同步,这里你不需要。)

monad堆叠的顺序可能很重要 - 但在这种情况下,它不会。如果你有List monad和Error monad之类的东西,那么根据堆叠顺序,错误要么在列表中只有一种可能性,要么在列表中所有可能性。对于您的情况,没有任何效果会根据堆栈顺序而改变。

...这是幸运的,因为没有用于将物品变成ST的变压器。所以ST 已经成为内部monad。

说了这么多,再说一遍,我认为你真的不需要monad堆栈。我认为一个简单的STRef会做。

答案 1 :(得分:4)

使用ST时,你所拥有的任何数组或引用都不是State monad意义上的 state :它们永远不会被修改!你可以把它们想象成一个指针;指针是不变的,虽然它指向的东西可能会改变。因此,您可以将数组或引用或其他任何内容作为函数参数传递给ST操作。如果您希望StateT操作需要返回不同的数组而不是传递的数组,那么ST机制将是合适的 - 即不仅修改现有数组而且创造一个新鲜的。由于通常不是这种情况,StateT不合适。

如果你真的想要一个monad变换器堆栈,你可以把你的数组和引用放到ReaderT monad的环境中。但这可能不是必要的。