I am new with Haskell, I have a question
h x = x : (h x)
g xs = [head xs, head xs - 1]
What is the result of running g(h 2)
assuming the semantics is call-by-name and call-by-value ?
I am new with Haskell, I have a question
h x = x : (h x)
g xs = [head xs, head xs - 1]
What is the result of running g(h 2)
assuming the semantics is call-by-name and call-by-value ?
"Call by name" is non-memoizing non-strict evaluation strategy where the value(s) of the argument(s) need only be found when actually used inside the function's body, each time anew:
h x = x : (h x)
g xs = [head xs, head xs - 1]
g (h 2) = let {xs = (h 2)} in [head xs, head xs - 1]
= [let {xs = (h 2)} in head xs, let {xs = (h 2)} in head xs - 1]
= [head (h 2), let {xs = (h 2)} in head xs - 1]
= [head (let {x = 2} in x : (h x)}), let {xs = (h 2)} in head xs - 1]
= [let {x = 2} in x, let {xs = (h 2)} in head xs - 1]
= [2, let {xs = (h 2)} in head xs - 1]
= ....
"Call by need" is memoizing non-strict a.k.a. "lazy" evaluation strategy where the value(s) of the argument(s) need only be found when used inside the function's body for the first time, and then are available for any further reference:
h x = x : (h x)
g xs = [head xs, head xs - 1]
g (h 2) = let {xs = (h 2)} in [head xs, head xs - 1]
= let {xs = (2 : (h 2))} in [head xs, head xs - 1]
= let {xs = (2 : (h 2))} in [2, head xs - 1]
= ....
"Call by value" is strict evaluation strategy where the value(s) of the argument(s) must be found before entering the function's body:
h x = x : (h x)
g xs = [head xs, head xs - 1]
g (h 2) = let {xs = (h 2)} in [head xs, head xs - 1]
= let {xs = (2 : (h 2))} in [head xs, head xs - 1]
= let {xs = (2 : (2 : (h 2)))} in [head xs, head xs - 1]
= let {xs = (2 : (2 : (2 : (h 2))))} in [head xs, head xs - 1]
= ....
All the above assuming g (h 2)
is entered at the GHCi prompt and thus needs to be printed in full by it.
Let's go in step by step fashion.
First of all, h x = x : (h x)
is recursive. The function h
is defined in terms of itself: given some x
it puts it on the list
, which is x : x : x : ...
infinite. In other words, since reursion never termintes, list can not be finite. Yet it does not hang forever. Why?
Because Haskell is lazy. It does not evaluate any expression unsless absolutely necessary to. In your case no infinite lists gets created in memory at all, event if h 2
is called. Why?
Because g
requests only two first elements of a given list named xs
. Haskell is smart enough to expand infinite list only for as long as needed and not waste resources. Generally, that's the benefit of laziness. It works with other expressions as well, not only lists.