如何通过隐藏“状态”来编写没有 IO 类型 sig 的 haskell 函数变化
I wrote a function in haskell that takes a few parameters like Word32, String (ignore currying) and outputs IO Word32. Now, this is a function in the true sense: for the same inputs, the output will always be the same. There are no side-effects. The reason the function returns IO Word32 instead of Word32 is that the function updates many 32 bit Linear Feedback Shift registers (lfsr) and other registers several times in a loop in order to compute the final Word32 output.
My question is this: Given that this function effectively has no side-effects, is it possible to hide those register updates inside the function implementation so that the function returns Word32 and not IO Word32?如果是这样,怎么办?
I wrote a function in haskell that takes a few parameters like Word32, String (ignore currying) and outputs IO Word32. Now, this is a function in the true sense: for the same inputs, the output will always be the same. There are no side-effects. The reason the function returns IO Word32 instead of Word32 is that the function updates many 32 bit Linear Feedback Shift registers (lfsr) and other registers several times in a loop in order to compute the final Word32 output.
My question is this: Given that this function effectively has no side-effects, is it possible to hide those register updates inside the function implementation so that the function returns Word32 and not IO Word32? If so, how?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
是的!哈斯克尔可以做到这一点。
ST monad
如果您实际上使用可变状态(寄存器),这些状态对函数外部的观察者完全隐藏,那么您就处于 ST monad,仅用于记忆效应的 monad。你通过
runST
进入ST世界,当你退出该函数时,所有效果保证不可见。它正是处理本地可变状态的正确计算环境。
纯功能状态:状态单子
但是,如果您实际上并未改变寄存器或单元格,而是多次更新纯功能值,则可以使用更简单的环境:状态 monad。这不允许状态可变,但会产生本地状态的错觉。
IO 和 unsafePerformIO
最后,如果您有本地可变效果,例如在
ST
monad 中,但由于某种原因,您将需要对其进行 IO 操作状态(例如通过 FFI 调用),您可以使用unsafePerformIO
而不是runST
来模拟ST
monad,几乎具有同样的安全性>, 介绍一下当地的IO环境。由于 IO monad 没有很好的类型来强制执行抽象,因此您需要手动确保副作用不会被观察到。Yes! Haskell can do this.
The ST monad
If you actually use mutable state (registers), that are entirely hidden from the observer outside the function, then you are in the ST monad, a monad for memory effects only. You enter the ST world via
runST
, and when you exit the function, all effects are guaranteed to not be visible.It is precisely the right computational environment for working with local, mutable state.
Purely functional state: the State monad
If, however, you're not actually mutating registers or cells, but rather updating a purely functional value many times, a simpler environment is available: the State monad. This doesn't allow mutable state, but gives an illusion of local state.
IO, and unsafePerformIO
Finally, if you have local, mutable effects, like in the
ST
monad, but for some reason or another, you are going to need IO operations on that state (such as via an FFI call), you can simulate theST
monad, with almost as much safety, by usingunsafePerformIO
, instead ofrunST
, to introduce a local IO environment. As the IO monad doesn't have nice types to enforce abstraction, you will need to manually assure yourself that the side effects will not be observable.如果您使用 FFI 导入该函数,只需从返回类型中删除 IO 即可。否则,使用 unsafePerformIO :: IO a -> a 来自
System.IO.Unsafe
。请注意,该函数是 Haskell 中最危险的函数之一。如果您对后果不太清楚,请不要使用它。但就你的目的而言,似乎没问题。If you imported that function using the FFI, just remove the
IO
from the return type. Else, useunsafePerformIO :: IO a -> a
fromSystem.IO.Unsafe
. Please note, that this function is one of the most dangerous functions in Haskell. Don't use it, if you're not really shure about the consequences. But for your purpose, it seems okay.是的,这将是 unsafePerformIO 的合法使用。
但只有当您确实确定没有明显的影响时才可以。
Yes, this would be a legitimate use of unsafePerformIO.
But it's only OK if you are really sure there are no visible effects.