I am wondering why :sprint
reports xs = _
in this case:
Prelude> xs = map (+1) [1..10]
Prelude> length xs
10
Prelude> :sprint xs
xs = _
but not in this case:
Prelude> xs = map (+1) [1..10] :: [Int]
Prelude> length xs
10
Prelude> :sprint xs
xs = [_,_,_,_,_,_,_,_,_,_]
Note: I am running ghci
with -XNoMonomorphismRestriction
. Does it have to do with the fact that the type of xs
is polymorphic in the first case but not in the second? I'd like to know what's going on internally.
The gist is that the with the polymorphic
xs
it has a type of the formtypeclasses under the hood are really just functions, they take an extra argument that GHC automatically fills that contains a record of the typeclasses functions. So you can think of
xs
having the typeSo when you run
It has to choose some value for
a
, and find the correspondingNumDict
value. IIRC it'll fill it withInteger
, so you're actually calling a function with and checking the length of the resulting list.When you then
:sprint
xs
, you once again fill in that argument, this time with a fresh type variable. But the point is that you're getting an entirely different list, you gave it a differentNumDict
so it's not forced in any way when you calledlength
before.This is very different then with the explicitly monomorphic list since there really is only one list there, there's only one value to force so when you call length, it forces it for all future uses of
xs
.To make this a bit clearer, consider the code
This is really what type classes are like under the hood, GHC would automatically fill in that first
Smash a
argument for us. Now your first example is likejoin
, we can't make any assumptions about what the output will be as we apply it to different types, but your second example is more like