gpt4 book ai didi

Haskell:懒惰的 `Control.Monad.ST.Lazy` monad 有多懒惰?

转载 作者:行者123 更新时间:2023-12-03 15:15:41 25 4
gpt4 key购买 nike

我一直在试验严格和懒惰的ST monads,我并不清楚每个人的懒惰程度。
例如,使用惰性 Control.Monad.State.Lazy monad 我们可以写:

main = print $ (flip evalState) "a" $ do
forever $ put "b"
put "c"
get

这工作正常并输出 "c" .双重的,严格的 Control.Monad.State.Strict 的代码相同变体将运行 put "b"永远,并挂起。

直觉上,我希望 ST 具有相同的对偶性。单子(monad)。也就是说,给定代码:
main = print $ S.runST $ do
r <- newSTRef "a"
forever $ writeSTRef r "b"
writeSTRef r "c"
readSTRef r
Control.Monad.ST.Lazy应该输出 "c" , 而 Control.Monad.ST.Strict应该挂。但是,它们都无限循环。我认为这是有正当理由的,例如:向后阅读,引用 r在最后一个 writeSTRef 的时间尚未分配叫做。但不知何故,感觉我们可以做得更好。

最佳答案

How lazy is the lazy Control.Monad.ST.Lazy monad?



令人惊讶的是,它完全是懒惰的。但是 Data.STRef.Lazy不是。
ST.Lazy懒惰

让我们先关注另一个例子:
import qualified Control.Monad.ST as S
import qualified Control.Monad.ST.Lazy as L

squared :: Monad m => m [Integer]
squared = mapM (return . (^2)) [1..]

ok, oops :: [Integer]
ok = L.runST squared
oops = S.runST squared

即使 okoops应该做同样的事情,我们只能得到 ok的元素.如果我们尝试使用 head oops ,我们会失败。然而,关于 ok ,我们可以取任意多个元素。

或者,要将它们与非单子(monad)平方列表进行比较,它们的行为类似于:
ok, oops :: [Integer]
ok' = map (^2) [1..]
oops' = let x = map (^2) [1..] in force x -- Control.DeepSeq.force

这是因为严格版本会评估所有状态操作,即使我们的结果不需要它们。另一方面,惰性版本会延迟操作:

This module presents an identical interface to Control.Monad.ST, except that the monad delays evaluation of state operations until a value depending on them is required.


readSTRef 呢? ?

现在让我们再次关注您的示例。请注意,我们可以使用更简单的代码获得无限循环:
main = print $ L.runST $ do
forever $ return ()
r <- newSTRef "a"
readSTRef r

如果我们添加一个额外的 return在最后 …
main = print $ L.runST $ do
forever $ return ()
r <- newSTRef "a"
readSTRef r
return "a"

… 一切都很好。显然 newSTRef 中有一些严格的东西或 readSTRef .让我们看看他们的 implementation :
import qualified Data.STRef as ST

newSTRef = strictToLazyST . ST.newSTRef
readSTRef = strictToLazyST . ST.readSTRef
writeSTRef r a = strictToLazyST (ST.writeSTRef r a)

还有罪魁祸首。 Data.STRef.Lazy实际上是通过 Data.STRef 实现的, 这意味着 Control.Monad.ST.Strict . strictToLazyST 只隐藏这个细节:

strictToLazyST :: ST.ST s a -> ST s a
strictToLazyST m = ST $ \s ->

Convert a strict ST computation into a lazy one. The strict state thread passed to strictToLazyST is not performed until the result of the lazy state thread it returns is demanded.



现在让我们把事情放在一起:
  • main , 我们要 print懒人给出的值ST计算
  • 懒惰的ST计算值由惰性 readSTRef 给出
  • 懒惰的readSTRef实际上是作为严格的 readSTRef 的惰性包装器实现的。
  • 严格的readSTRef评估状态,就好像它是一个严格的
  • forever $ return ()的严格评价咬我们

  • 所以当前 ST.Lazy够懒。 这是Data.STRef.Lazy这太严格了。 只要 Data.STRef.Lazy基于 strictToLazyST ,这种行为会持续下去。

    关于Haskell:懒惰的 `Control.Monad.ST.Lazy` monad 有多懒惰?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24072934/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com