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

hdb*_*db3 3 arrays haskell mutable state-monad monad-transformers

我正在构建代码以获得理解,实际上是Solitaire求解器.我有一个简单的暴力实现,它使用状态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吗?

Mat*_*hid 5

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

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

在单子堆叠顺序可以重要-但在这种情况下,它没有.如果你有这样的事情的清单单子和错误单子,然后根据不同的堆叠顺序上的错误或者失败,这个名单仅仅是一种可能性,或者所有列表中的可能性.对于您的情况,没有任何效果会根据堆栈顺序而改变.

...幸运的是,因为没有用于将物品转换成ST的变压器.ST 必须是内在的monad.

说了这么多,我认为你真的不需要monad堆栈.我认为一个简单的STRef意志.

  • 你可以定义`type STState s st = ReaderT (STRef s st) (ST s)`,然后通过`runSTState sts = newSTRef initState >>= runReaderT sts`运行`STState`计算。这种方法与手动传递 `STRef` 是同构的,但可能更美观。当然,那时你最好只使用`StateT st (ST s)`。 (2认同)

Dan*_*ner 5

使用时ST,任何数组或引用您有没有真正说明State这个词的单子感:他们决不会被修改!你可以把它们想象成一个指针;指针是常量,虽然它指向的东西可能会改变。因此,您可以将数组或引用或任何内容ST作为函数参数传递给您的操作。StateT如果您希望ST操作需要返回传递的数组不同的数组,则该机制将是合适的——即不仅修改现有数组,而且创建一个新数组。由于一般情况并非如此,StateT是不合适的。

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