更严格的严格状态Monad

时间:2015-01-18 18:55:05

标签: haskell lazy-evaluation state-monad

严格状态monad使用:

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

但是这仍然会泄漏内存,因为as'未被评估。例如,我们可能有一个函数f,它将一个大对象作为输入并快速返回(a, s'),但只要a未被评估,f的输入就不能是GC的。

一个可能的解决方案是让f返回seq a (a, s'),但如果我们使用类似MonadRandom之类的内容,则不可能这样做,并且状态被封装远离f {1}}。是否有这样定义的版本:

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

这已存在于任何地方的库中吗?

1 个答案:

答案 0 :(得分:6)

根据monad身份法,

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。我不确定如果不这样做会导致某种破损,但如果确实如此,我不会感到惊讶。