7

我在 haskell 中编写了一个函数,它接受一些参数,如 Word32、String(忽略柯里化)并输出 IO Word32。现在,这是一个真正意义上的函数:对于相同的输入,输出总是相同的。没有副作用。该函数返回 IO Word32 而不是 Word32 的原因是该函数在一个循环中多次更新许多 32 位线性反馈移位寄存器 (lfsr) 和其他寄存器,以计算最终的 Word32 输出。

我的问题是:鉴于此函数实际上没有副作用,是否可以在函数实现中隐藏这些寄存器更新,以便函数返回 Word32 而不是 IO Word32?如果是这样,怎么做?

4

3 回答 3

13

是的!Haskell 可以做到这一点。

ST 单子

如果您实际上使用了对函数外部的观察者完全隐藏的可变状态(寄存器),那么您就在ST monad中,这是一个仅用于记忆效应的 monad。通过 进入ST世界runST,退出该功能时,保证所有效果不可见。

这正是处理本地可变状态的正确计算环境。

纯功能状态:State monad

但是,如果您实际上并没有改变寄存器或单元格,而是多次更新纯函数值,则可以使用更简单的环境:State monad。这不允许可变状态,但会产生本地状态的错觉。

IO 和 unsafePerformIO

最后,如果你有本地的、可变的效果,比如在STmonad 中,但由于某种原因,你需要对该状态进行 IO 操作(例如通过 FFI 调用),你可以模拟STmonad,几乎就像通过使用unsafePerformIO,而不是runST,引入本地 IO 环境,更加安全。由于 IO monad 没有很好的类型来强制抽象,因此您需要手动确保自己不会观察到副作用。

于 2011-05-20T15:38:59.553 回答
5

如果您使用 FFI 导入该函数,只需IO从返回类型中删除 。否则,使用unsafePerformIO :: IO a -> afrom System.IO.Unsafe。请注意,这个函数是 Haskell 中最危险的函数之一。不要使用它,如果你对后果不是很清楚。但就您的目的而言,这似乎还可以。

于 2011-05-20T15:37:03.803 回答
3

是的,这将是对 unsafePerformIO 的合法使用。但只有当你真的确定没有明显的影响时才可以。

于 2011-05-20T15:38:04.093 回答