问题描述
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 构造函数,而不会评估所有内容。
解决方法
正如我所见,只有 Map
构造函数会被评估,而所有内容都将不被评估。
在内部,Map
类型是使用严格树实现的。要么评估整个树脊,要么都不评估。这是库代码的片段:
data Map k a = Bin {-# UNPACK #-} !Size !k a !(Map k a) !(Map k a)
| Tip
严格注释 (!
) 可防止将未评估的值存储为子树。因此,如果我们将 Map k a
值评估为弱头部范式,我们实际上会完全评估树脊。
@Input() newData: any;
中的 Map
不是地图构造函数。它是一个模块名称。函数 insert :: Ord k => k -> a -> Map k a -> Map k a
在这里被调用。由于调用了 Map.insert
,它的结果将在 return ()
被计算为组合 IO 操作中的下一个计算步骤之前被评估为 WHNF。详情可咨询the source of insert
。它通过爆炸模式等做了很多强制。