2016-11-20 58 views
2

我這是在玩弄代碼:爲什麼:即使當我評估變量時,sprint顯示WHNF?

*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

+0

可能重複[:sprint for polymorphic values?](http://stackoverflow.com/questions/21518584/sprint-for-polymorphic-values) – Cactus

回答

4

簡短的回答是,: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'直至我們可以:sprintData.Map.Map數據結構的位置,因爲還尚未指定我們需要哪個和Ord實例。

作爲一個反例:

λ> 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中的交叉而讓我們驚訝。

+0

哦..我不知道..謝謝 –

+0

但是當我做了'seq yy' ..它打印了值..現在不應該評估'y'的'thunk'嗎?是否因爲y的多態特性,'sprint'仍然不會顯示我們? –

+2

實際上'seq y()'會將'y'專用於默認類型,所以它會評估'y'NumInteger NumInteger OrdInteger'(到'Bin'構造函數)。但是這並不改變'y'在內部是一個函數的事實,所以':sprint'將始終顯示爲'_'。 –