【问题标题】:Stricter Strict State Monad更严格的状态单子
【发布时间】:2015-01-18 18:55:05
【问题描述】:

严格的状态 monad 是这样定义的:

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

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

一种可能的解决方案是让f 返回seq a (a, s'),但如果我们使用MonadRandom 之类的东西,并且状态与f 隔离开来,这并不总是可行的。是否有这样定义的版本:

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

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

【问题讨论】:

  • @GabrielGonzalez 在制作更严格的变压器方面做了一些工作,例如more strict WriterT
  • 我很想只在s 上严格执行此操作。如果需要严格的a,我认为调用者可以简单地m >>= \ !a -> ... 达到相同的效果。
  • a 中设置严格会违反单子定律,所以你不想那样做。当在s 中严格要求时,您还必须将return 更改为return x = State $ \ !s -> (x, s),否则它会保留身份规则。
  • 试试看。您可能会违反单子定律(并引入例如立即失败)。
  • @dfeuer 我想你可以把你的评论变成一个答案,把它作为一个未回答的问题来结束?

标签: haskell lazy-evaluation state-monad


【解决方案1】:

根据单子恒等律,

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)

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

!_ <- get

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

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

编辑

即使这个定义对我来说也有点奇怪;我希望 lambda 强制状态,而不是 case。我不确定不这样做是否会导致某种损坏,但如果确实如此,我也不会感到惊讶。

【讨论】:

  • 在存在 seq 的情况下,所有 monads 都无法遵守法律(也懒惰的 WriterState),请参阅 this answer
  • @PetrPudlák,是的,这是一件可悲的事情。在合理的情况下,我们仍然应该尽我们所能,对吧?
  • @PetrPudlák,特别是,我认为最好确保您的Monad 实例遵守法律只要没有人使用它们会愚蠢的seq 技巧
  • 愚蠢的 seq 技巧在基础版本 4.8 中将更加令人讨厌,因为 Identity 将充分利用人们不这样做的优势,定义如 fmap=coercefoldMap=coerce、@987654348 @ 和 foldl'=coerce
  • 参见coinductioncorecursionTotal functional programming。也值得阅读链接的the paper。特别是,归纳数据类型总是有限的并且没有底部,协导数据类型(codata)可以是无限的,但又没有底部。这真的很好,可以在语法上强制执行。所以seq 只能改变性能,不能改变结果。
猜你喜欢
  • 2021-12-03
  • 1970-01-01
  • 1970-01-01
  • 2014-11-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-08-18
  • 1970-01-01
相关资源
最近更新 更多