2

This is the code i am playing around with :

*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>

I can not understand why :sprint y is always showing _ ?

I have

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

and ghc 7.10.3

Cactus
  • 27,075
  • 9
  • 69
  • 149
Ashish Negi
  • 5,193
  • 8
  • 51
  • 95
  • Possible duplicate of [:sprint for polymorphic values?](http://stackoverflow.com/questions/21518584/sprint-for-polymorphic-values) – Cactus Nov 21 '16 at 02:30

1 Answers1

4

The short answer is that :sprint is leaky.

The long answer is because your y value is polymorphic:

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

In this case seq y () will not be able to evaluate down to the map. Imagine the type of y as the runtime would represent it: y' :: NumDict k -> NumDict t -> OrdDict k -> Map k (t, String). seq y' () would fail to evaluate y' down to the point where we could :sprint its Data.Map.Map data structure because still have yet to specify which Num and Ord instances we want.

As a counter-example:

λ> 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

Here we see that by eliminating the polymorphism we get the expected behavior. Which circles us back to :sprint as a leaky command: to correctly predict its output it requires us to know more about the runtime representation of values that we think we should; it surprises us by living at the intersection of polymorphic literals, type inference, and thunks.

hao
  • 10,138
  • 1
  • 35
  • 50
  • but when i did `seq y y`.. it printed value.. should not now the `thunk` of `y` be evaluated ? Is it that `:sprint` would still not show us that because of polymorphic nature of y ? – Ashish Negi Nov 20 '16 at 10:22
  • 2
    Actually `seq y ()` will specialize `y` to the default types, so it will evaluate `y' NumInteger NumInteger OrdInteger` (to a `Bin` constructor). But that doesn't change the fact that `y` is internally a function so `:sprint` will always display it as `_`. – Reid Barton Nov 20 '16 at 15:23