Haskell 中“do”之外的 ST Monad 用法?

Fun*_*tor 1 haskell

我在符号上下文中看到了很多 ST monad 的例子do;然而,由于这不适合我的目的,我尝试在线程之外newSTRef使用ST monad 。modifySTRefdo

\n

该类型是由 VSCode 的 HLS 自动添加的。

\n
ref :: ST s (STRef s Integer)\nref = newSTRef (1)\n\nx :: ST s ()\nx = modifySTRef ref 2\n
Run Code Online (Sandbox Code Playgroud)\n

错误:ref在最后一行

\n
Couldn't match expected type \xe2\x80\x98STRef s a0\xe2\x80\x99\n            with actual type \xe2\x80\x98ST s0 (STRef s0 Integer)\xe2\x80\x99\n
Run Code Online (Sandbox Code Playgroud)\n

好吧,我当然可以看到错误说类型不匹配,但我不知道如何修复它。

\n

ST Monad 之外的正确用法是什么do

\n

编辑:

\n

我的目的没有do

\n
    \n
  1. 就像提到的那样,do仅仅是一种语法糖,我通常想避免它,以便以更简单的功能方式编写代码。

    \n
  2. \n
  3. 获取可变对象的目的是为了开发FRP,而ref在单线程中顺序定义和更新do是没有用的。

    \n
  4. \n
\n

rad*_*row 5

这里的问题是modifySTRef需要一个STRef s a,而不是一个ST s (STRef s a)ST旨在利用 monad 属性来确保可变操作不被滥用,因此所有修改只能在ST上下文中发生。因此,您需要利用上下文的力量来提取纯STRef引用。

通常你会do这样:

x :: ST s ()
x = do
  refv <- ref
  modifySTRef refv 2
Run Code Online (Sandbox Code Playgroud)

但既然你想避免这种糖,你可以做正确的脱糖操作:

x :: ST s ()
x = refv >>= \refv -> modifySTRef refv 2
Run Code Online (Sandbox Code Playgroud)

您可以在此处阅读有关do符号及其解析方式的更多信息


注释:请注意,您的代码没有这样的全局变量。每次在 ST 上下文中调用时newSTRef都会分配一块新的 RAM 。因此,在这个例子中实际上什么也没做(除了浪费一些内存和 GC 时间)。x

如果您打算保留参考文献,则必须将其“放在手中”,例如放在包装纸中ReaderT

  • @JosephSible-ReinstateMonica 是的。事实上,它甚至更进一步:“ST s ()”类型的所有操作都明显等同于“pure ()”(直到定义)。 (3认同)