Consider the famous
fibs = 0 : 1 : zipWith (+) fibs (tail fibs)
Suppose that, to avoid the monomorphism restriction, this is annotated with:
fibs :: Num a => [a]
This seems to imply that at runtime, a list value fibs
does not really exist, but rather a function that computes the list anew each time an element of fibs
is picked?
The question is how such cases are actually handled in different Haskell implementations you know of.
--- ADDED ---- I feel that I must elaborate a bit more. Consider:
fibsInteger :: [Integer]
fibsInteger = 0: 1: zipWith (+) fibsInteger (tail fibsInteger)
and suppose during program execution the value
(fibsInteger !! 42)
needs to be evaluated. In that case I would expect that subsequent evaluations like that would find that the first 43 elements of fibsInteger
are already evaluated. This implies also that fibsInteger
itself and the first 42 tails of it are already in WHNF.
Yet that would not be possible with a polymorphic fibs
, as far as I can see. FUZxxl's remark
because a typeclass usually introduces a new argument containing a dictionary with the functions of that typeclass
seems to support my view that a value like fibs
effectively appears as function at runtime?
If this were so, then an application like ((maximum . map (fibs!!)) [100000 .. 101000] :: Integer)
shold take noticeably longer to evaluate than the non-polymorphic variant ((maximum . map (fibsInteger!!)) [100000 .. 101000] :: Integer)
because the first 100000 numbers will have to be recomputed each time.
(Unfortunately, I can't try this out at this time)