3

I am trying to figure out, how lazy evaluation works and I've tried as following:

Prelude> a = [1,2,3,5,6]
Prelude> b = map (\x -> x * 8) a
Prelude> :sprint b
b = _
Prelude> b
[8,16,24,40,48]
Prelude> :sprint b
b = _ 

The question is, why the last line does not show the evaluated list? I evaluated a line before.

softshipper
  • 32,463
  • 51
  • 192
  • 400
  • 3
    After a preliminary bit of research, I've found this: https://stackoverflow.com/questions/35198306/why-sprint-always-prints-a - and think Zeta's comment on the accepted answer is relevant to your case – Robin Zigmond Feb 13 '19 at 16:31
  • at GHCi prompt, type: `> :set +t`. it then will be reporting the type of every definition you enter. after `let xs = [1,2,3]` it would print `xs :: Num a => [a]`. This means `xs` is not a *monomorphic-type value*, but a polymorphic-type *definition*. Since there's no value there, there's nothing to be retained in memory. Its value will be calculated each time anew, because GHCi doesn't know which specific type it will be asked to calculate the value at. – Will Ness Feb 13 '19 at 20:30
  • But if you entered `let xs = [1,2,3] :: [Int]`, you'd get back `xs :: [Int]`. Since the type is specific (aka monomorphic i.e. there's no *poly*-morphism), there's a value to retain after calculating it just once. – Will Ness Feb 13 '19 at 20:30

1 Answers1

8

Because b is basically a function from Num a dictionary to [a] for some a. If this were a concrete type then it would be as you expected:

let a Prelude> let a = [1..4] :: [Int]
Prelude> let b = map (*8) a
Prelude> :sprint b
b = _
Prelude> b
[8,16,24,32]
Prelude> :sprint b
b = [8,16,24,32]

EDIT

Side by side it will hopefully be even more apparent:

Prelude> let a = [1..4]
Prelude> :t a
a :: (Num a, Enum a) => [a]
Prelude> let poly_b = map (*8) a
Prelude> let concrete_b = map (* (8 ::Int)) a
Prelude> :sprint poly_b
poly_b = _
Prelude> :sprint concrete_b
concrete_b = _
Prelude> poly_b
[8,16,24,32]
Prelude> concrete_b
[8,16,24,32]
Prelude> :sprint poly_b
poly_b = _
Prelude> :sprint concrete_b
concrete_b = [8,16,24,32]

EDIT 2: It occurs to me that the monomorphism restriction, or lack thereof in the REPL, could be causing some confusion. In compiled code the value in a let statement would take on a single concrete type and not be polymorphic, thus not have this "problem" at all:

Prelude> :set -XMonomorphismRestriction
Prelude> let a = [1..4]
Prelude> let b = map (*8) a
Prelude> :sprint b
b = _
Prelude> b
[8,16,24,32]
Prelude> :sprint b
b = [8,16,24,32]
Thomas M. DuBuisson
  • 64,245
  • 7
  • 109
  • 166