序列部分应用的Monadic动作

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了序列部分应用的Monadic动作相关的知识,希望对你有一定的参考价值。

我知道这可能是显而易见的,但我的google-fu在这里让我失望。我有一个类型的动作列表:

import Data.Vector.Mutable (STVector)
[STVector s a -> ST s ()]

也就是说,一组采取启动MVector并以某种方式改变它的动作

我也有一个起始向量

import Data.Vector         (Vector, thaw, freeze)
v :: Vector a

解冻v后,如何将这些动作排序为最终结果?

doIt :: forall s. Vector a -> [STVector s a -> ST s ()] -> Vector a
doIt v ops = runST $ do
  v' <- thaw v
  -- do all the things to v'
  unfreeze v'

如果上下文有帮助,我正在尝试代码的第16天谜题(第2部分),所以ops是一个很长的突变列表,我实际上需要经历十亿次。我希望能够使用replicateM_来做到这一点,但无法看到如何提供起始值。我同样认为foldM_会工作,但我似乎无法得到它来检查。也许我在做一些根本错误的事情?我不能说我了解ST monad的前后任务。

答案

您正在寻找的操作是traverse_。它访问数据结构中的每个值,应用具有monadic返回类型的函数,并在丢弃其结果的同时对它们的效果进行排序。 “丢弃他们的结果”部分很重要。这意味着在这种情况下traverse_的返回类型将是ST s ()而不是ST s [()]。差异很大。这意味着该操作不会建立一个巨大的()值列表,最终扔掉。

您要传递给traverse_的函数是指“将函数应用于v'”的函数。这可以写成f -> f v',但有一个较短的版本,这是惯用的,并使用$运算符。请注意,您可以将上面的lambda重写为f -> f $ v',可以将其重写为($ v')部分。

所以你有traverse_ ($ v') ops,这是正确的操作,但它仍然不会打字检查。那是因为runST的类型,这要求s中的ST s类型是多态的。使用您的类型签名,sdoIt的调用者选择。要使其工作,您需要通过确保{-# LANGUAGE RankNTypes #-}位于文件的顶部,然后将类型更改为Vector a -> (forall s. [STVector s a -> ST s ()]) -> Vector a来启用RankNTypes扩展。这种s类型变量范围的缩小要求s在传递给doIt的值中具有多态性。有了这个限制,runST将通过上述操作成功进行检查。

有关为什么runST具有如此有趣类型的更多信息,请参阅Lazy Functional State Threads,该文章介绍了ST类型并展示了它如何用于约束外部纯接口内的可变性。

以上是关于序列部分应用的Monadic动作的主要内容,如果未能解决你的问题,请参考以下文章

Scalaz(33)- Free :算式-Monadic Programming

Monadic Function_Haskell笔记12

怎么通过程序控制unity3d人物动作

解密体育背后AI黑科技:花样滑冰动作识别多模视频分类和精彩片段剪辑

引用向量的部分片段?

片段交易动画完成后执行动作