Reputation: 93
I'm trying to understand recursive data, and I'm a little confused. I tried this:
m = 1 : map (+1) m
and this produced a list identical to [1..]
. I tried to complete the evaluation procedure like this:
m = 1 : map (+1) m
= 1 : map (+1) (1 : map (+1) m)
= 1 : 2 : map (+1) (map (+1) m)
= 1 : 2 : map (+1) (map (+1) (1 : 2 : map (+1) (map (+1) m)) )
= 1 : 2 : map (+1) (2 : map (+1) (2 : (map (+1) (map (+1) m)) )
= 1 : 2 : 3 : map (+1) (map (+1) (2 : (map (+1) (map (+1) m)))
= 1 : 2 : 3 : map (+1) (3 : map (+1) ( (map (+1) (map (+1) m))) )
= 1 : 2 : 3 : 4 : map (+1) (map (+1) ( (map (+1) (map (+1) m)) ))
= ...
there are a lot of map (+1)
stuff in the tail and increasing with the procedure. Are there really so many map (+1)
and repeated calculation of map (+1) ...
? I've read other posts mentioning thunks, but how to actually relate them all together? Thank you very much.
Upvotes: 1
Views: 123
Reputation: 54058
What would happen is more like the following
m = 1 : map (+1) m
1 : map (+1) (1 : _)
^------------<| Points to the same thunk in memory
1 : a : map (+1) (a : _) where a = ((+1) 1)
^------------<|
1 : 2 : map (+1) (2 : _)
^------------<|
1 : 2 : a : map (+1) (a : _) where a = ((+1) 2)
^------------<|
1 : 2 : 3 : map (+1) (3 : _)
^------------<|
1 : 2 : 3 : a : map (+1) (a : _) where a = ((+1) 3)
^------------<|
1 : 2 : 3 : 4 : map (+1) (4 : _)
^------------<|
The next element in the list passed to map
always points back to the element map
is about to generate.
However, it is important to note that the Haskell specification states that it must be lazy, but the manner in which the laziness is implemented is up to the compiler. It may choose to optimize away a lot of this into a simple loop in assembly, or depending on how the output is used, it might do some loop fusion to combine several traversals into one.
Upvotes: 1