严格状态monad使用:
定义m >>= k = State $ \s ->
case runState m s of
(a, s') -> runState (k a) s'
但是这仍然会泄漏内存,因为a
和s'
未被评估。例如,我们可能有一个函数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'
这已存在于任何地方的库中吗?
答案 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
。我不确定如果不这样做会导致某种破损,但如果确实如此,我不会感到惊讶。