在 IO-Monad 中访问状态

Accessing state in an IO-Monad

我正在尝试在 IO 操作中访问 State Monad 的状态。

更具体地说:我正在尝试使用来自 System.Posix.Signals which requires IO, however, I'd like to do different actions and change the state from inside the handler. I took a look at unliftioinstallHandler 编写一个依赖于状态的信号处理程序,但我读到 State-Monads 不应该被解除。

这可能吗?我更多的是寻找解释而不是“复制粘贴”解决方案。如果在 IO 中解除 State 不起作用,解决方案会是什么样子,因为当有人想在 IO 中进行一些状态感知处理时?

State a b 类型的值不包含状态。它只是一个封装的函数,可以提供一个结果状态和一个结果,如果你传递一个起始状态(使用 runState 函数。没有办法从外部访问中间(或“当前”)状态这个功能。这就是 State Monad “纯粹”的原因。

您似乎打算拥有一个处理程序,它的行为并不总是相同(即使使用相同的参数调用),但取决于外部状态。这种行为是“不纯”的,不能只用单纯的手段来达到。因此,在这种情况下,您需要以某种方式封装不纯性,以便您可以从处理程序访问某些状态的“当前值”,而无需将当前值本身传递给处理程序。

正如您已经从评论中了解到的那样,为 IO 操作提供可变状态访问的首选工具正在使用 IORef。 IORefs 工作,因为 Haskell 运行时(传统上,至少在多线程之前)序列化 IO 操作。所以“当前值”的概念总是有意义的。在每次 IO 动作之后,每个 IORef 指向的值都是固定的。 IO 操作发生的顺序也是固定的,因为它需要是您将它们链接在 do 块中或使用 >>= 运算符的顺序。信号的处理由 Haskell 运行时以确定的方式执行,有点像每次链接两个 IO 操作时,运行时检查挂起的信号,并调用相应的处理程序。

如果您想编写以命令方式操作数据的代码(您可以有很多变量,甚至可以更新单个元素的数组),您可以将代码编写为 I/O action 并为它使用 IORefIOArray,但是有一个特殊的“精简版”IO 只支持可变状态,就像 I/O 一样,不能与环境。共享状态需要从这个特殊的 IO lite 的同一个“胶囊”内部创建、读取和写入,因此 运行 整个动作不与外部状态交互,而只与其内部状态 - 胶囊交互作为一个整体因此是纯粹的,即使胶囊内的单个陈述可以被认为是不纯粹的。这个精简版IO的名字叫做ST,是“state thread”的缩写。