更严格的严格状态 Monad

Stricter Strict State Monad

严格状态 monad 使用以下方式定义:

m >>= k = State $ \s ->
  case runState m s of
    (a, s') -> runState (k a) s'

但这仍然会泄漏内存,因为 as' 未被评估。例如,我们可能有一个函数 f 将一个大对象作为输入并快速 returns (a, s'),但只要 a 未计算 f 无法进行 GC。

一个可能的解决方案是 f return seq a (a, s'),但如果我们使用 MonadRandom 之类的东西,这并不总是可行的,并且状态是封装远离 f。有没有这样定义的版本:

m >>= k = State $ \s ->
  case runState m s of
    (!a, !s') -> runState (k a) s'

这是否已经存在于任何地方的图书馆中?

根据单子恒等律,

return a >>= const b = const b a = b

因此特别是,

return undefined >>= const b = b

如果 >>= 操作在结果值上是严格的,那将违反这条法律,所以你不应该那样做。

假设您改为这样做:

m >>= k = State $ \s ->
  case runState m s of
    (a, !s') -> runState (k a) s'

现在我们面临另一个恒等律:

m >>= return = m

例如,

return a >>= return = return a

所以如果return a >>= return是严格的状态,那么我们也必须有return a严格的状态!所以我们也需要重新定义return

return a = State $ \ !s -> (a, s)

请注意,您实际上不需要执行任何这些操作;如果你愿意,你可以使用通常的严格状态 monad,并写成

!_ <- get

在你想要强制状态的地方。你甚至可以写一个动作来做到这一点:

forceState :: Monad m => StateT s m ()
forceState = get >>= \ !_ -> return ()

编辑

连这个定义我都觉得有点陌生;我希望 lambda 强制状态,而不是 case。我不确定不这样做是否会导致某种破损,但如果确实如此,我也不会感到惊讶。