更严格的严格状态 Monad
Stricter Strict State Monad
严格状态 monad 使用以下方式定义:
m >>= k = State $ \s ->
case runState m s of
(a, s') -> runState (k a) s'
但这仍然会泄漏内存,因为 a
和 s'
未被评估。例如,我们可能有一个函数 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
。我不确定不这样做是否会导致某种破损,但如果确实如此,我也不会感到惊讶。
严格状态 monad 使用以下方式定义:
m >>= k = State $ \s ->
case runState m s of
(a, s') -> runState (k a) s'
但这仍然会泄漏内存,因为 a
和 s'
未被评估。例如,我们可能有一个函数 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
。我不确定不这样做是否会导致某种破损,但如果确实如此,我也不会感到惊讶。