为什么 :sprint 即使在我评估变量时也显示 WHNF?

Why :sprint is showing WHNF even when i evaluate the variable?

这是我正在玩的代码:

*Main DepthFirstSearch DivideAndConquer Fibonacci LongestEdgePathInDAG> let x = Data.Map.empty
*Main DepthFirstSearch DivideAndConquer Fibonacci LongestEdgePathInDAG> let y = Data.Map.insert 1 (1+1,"ashish") x
*Main DepthFirstSearch DivideAndConquer Fibonacci LongestEdgePathInDAG> :sprint x
x = containers-0.5.7.1:Data.Map.Base.Tip
*Main DepthFirstSearch DivideAndConquer Fibonacci LongestEdgePathInDAG> :sprint y
y = _
*Main DepthFirstSearch DivideAndConquer Fibonacci LongestEdgePathInDAG> y == x
False
*Main DepthFirstSearch DivideAndConquer Fibonacci LongestEdgePathInDAG> :sprint y
y = _
*Main DepthFirstSearch DivideAndConquer Fibonacci LongestEdgePathInDAG> seq y y
fromList [(1,(2,"ashish"))]
*Main DepthFirstSearch DivideAndConquer Fibonacci LongestEdgePathInDAG> :sprint y
y = _
*Main DepthFirstSearch DivideAndConquer Fibonacci LongestEdgePathInDAG>

我不明白为什么 :sprint y 总是显示 _

我有

➜  hsalgos git:(master) ✗ stack --version
Version 1.1.2 x86_64 hpack-0.14.0
➜  hsalgos git:(master) ✗

ghc 7.10.3

简短的回答是 :sprint 有漏洞。

长答案是因为您的 y 值是多态的:

λ> let y = insert 1 (1 + 1, "str") empty
λ> :t y
y :: (Num k, Num t, Ord k) => Map k (t, [Char])

在这种情况下 seq y () 将无法向下评估地图。想象一下 y 的类型,因为运行时会表示它:y' :: NumDict k -> NumDict t -> OrdDict k -> Map k (t, String)seq y' () 将无法评估 y' 到我们可以 :sprint 它的 Data.Map.Map 数据结构的地步,因为还没有指定哪个 NumOrd 我们想要的实例。

作为反例:

λ> let y = insert 1 (1 + 1, "str") empty :: Map Int (Int, String)
λ> :t y
y :: Map Int (Int, String)
λ> :sprint y
y = _
λ> seq y ()
()
λ> :sprint y
y = containers-0.5.6.2:Data.Map.Base.Bin
      1 1 (_,_) containers-0.5.6.2:Data.Map.Base.Tip
      containers-0.5.6.2:Data.Map.Base.Tip

这里我们看到,通过消除多态性,我们得到了预期的行为。这让我们回到 :sprint 作为一个漏洞命令:为了正确预测它的输出,它需要我们更多地了解我们认为应该的值的运行时表示;它生活在多态文字、类型推断和 thunk 的交汇处,这让我们感到惊讶。