【问题标题】:The example of strict evaluation from Simon Marlow's book "Parallel and Concurrent Programming in Haskell"来自 Simon Marlow 的《Haskell 中的并行和并发编程》一书中的严格评估示例
【发布时间】:2021-05-13 13:13:59
【问题描述】:

Simon Marlow 在他的《Haskell 中的并行和并发编程》一书中写道:

插入操作有这一行:

putMVar m (Map.insert name number book)

这会将未计算的表达式 Map.insert name number book 放在 MVar 中。 如果我们要连续执行许多插入操作,MVar 将建立一个大的未计算表达式链。 为了获得短暂的锁定并且没有空间泄漏,我们需要使用 一个技巧:

let book' = Map.insert name number book
putMVar m book'
seq book' (return ())

通过这个序列,我们在 MVar 中存储了一个未计算的表达式,但它在 putMVar 之后立即被计算。

我不明白。 seq a b 操作以弱头正常形式评估 a。所以会有未评估的表达。正如我所看到的,只有 Map 构造函数会被评估,而它的所有内容都不会被评估。

【问题讨论】:

    标签: haskell concurrency lazy-evaluation weak-head-normal-form


    【解决方案1】:

    正如我所见,只有 Map 构造函数会被评估,而它的所有内容都不会被评估。

    在内部,Map 类型是使用严格树实现的。要么评估整个树脊,要么不评估。这是库代码中的一个 sn-p:

    data Map k a  = Bin {-# UNPACK #-} !Size !k a !(Map k a) !(Map k a)
                  | Tip
    

    严格性注释 (!) 可防止将未评估的值存储为子树。因此,如果我们将 Map k a 值评估为弱头范式,我们实际上会完全评估树脊。

    【讨论】:

    • 谢谢!在提出问题之前,我必须先查看地图源代码;)
    【解决方案2】:

    Map.insert 中的Map 不是映射构造函数。它是一个模块名称。函数insert :: Ord k => k -> a -> Map k a -> Map k a 在这里被调用。由于调用了seq,其结果return () 被计算为组合IO 操作中的下一个计算步骤之前被评估为WHNF。详情可咨询the source of insert。它通过爆炸模式等进行了很多强制。

    【讨论】:

      最近更新 更多