4

我正在构建代码以获得理解,实际上是一个纸牌求解器。我有一个简单的蛮力实现,它使用 State monad,实际上只是为了证明我可以使用它(它只记录评估的每个动作的计数)。但是现在我想使用 Unboxed Mutable 数组来记录访问过的电路板,从而在我到达已经通过另一条路径访问过的电路板位置时对路径进行快捷评估。似乎 ST monad 不允许我线程隐式状态,但我必须使用 ST(或 IO)才能访问 Mutable 数组。所以看来我必须结合两个 Monad - State 来线程化状态(实际上将包括一个 Mutable 数组),另一个(ST)来获得 Mutable 数组函数。

  • 这是正确的吗?
  • 如果是这样,是否有比 Data.Array.ST/Control.Monad.ST/Control.Monad.ST 和 mtl 的(规范?)组合更好的选择?
  • 如果我真的走这条路,我堆叠 ST 和 State 的顺序是否重要?
  • 我是否应该考虑基于 ST 或 State 中的一个或两个来滚动我自己的单个 Monad 以避免使用 monad 转换器?
4

2 回答 2

5

使用时ST,您拥有的任何数组或引用都不是单子意义上的真正状态:它们永远不会被修改State您可以将它们视为指针;指针是不变的,尽管它指向的东西可能会改变。因此,您可以将数组或引用或其他任何内容ST作为函数参数传递给您的操作。如果您希望该操作需要返回与传递的数组不同的数组,则该StateT机制将是合适的——即不仅修改现有数组,而且创建一个新数组。既然一般情况下不是这样,也不合适。STStateT

如果你真的想要一个 monad 转换器堆栈,你可以将你的数组和引用放入ReaderTmonad 的环境中。但这可能不是必需的。

于 2014-02-20T22:48:08.163 回答
5

我不是 100% 确定 ST monad 是提高此类搜索任务性能的方法。但是假设它是......您可以通过将您想要保留的状态放入STRef. 您可以这样做而无需将多个 monad 混合在一起,这应该会使您的事情变得更加简单。

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

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

...这是幸运的,因为没有将东西变成 ST 的变压器。所以 ST必须是内部单子。

说了这么多,我不认为你真的需要一个单子堆栈。我认为一个简单的STRef就可以了。

于 2014-02-20T21:24:42.220 回答