-1

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 ?

Will Ness
  • 62,652
  • 8
  • 86
  • 167
Menma Yuna
  • 43
  • 1
  • 1
    `g (h 2) = [2,1]`. – Willem Van Onsem May 04 '20 at 20:36
  • 1
    The result will be `[2, 1]`, as you could easily verify by running it in GHCi. "call by name" vs "call by value" isn't really a distinction in Haskell, because values are immutable by default and it's only with mutable values that the distinction makes sense. – Robin Zigmond May 04 '20 at 20:37
  • That's why I confuse, I know one of it is [2,1], and another can be [2,1 ..] or Infinite loop. That's why I am not sure – Menma Yuna May 04 '20 at 20:39
  • Haskell works on immutable data, so "altering" the value of variable is not possible, hence you can not update the value and recall the function and expect that the result does/does not change. – Willem Van Onsem May 04 '20 at 20:40
  • 2
    Why do you think it is here `[2,1,...]`? Note that Haskell uses lazy programming, this is a concept that is "orthogonal" on the "calling style". – Willem Van Onsem May 04 '20 at 20:40
  • @RobinZigmond perhaps you thought of call by reference. call by name is non-memoized non-strict, call by need is memoized non-strict (a.k.a. "lazy"), call by value - strict evaluation strategy. "call by value Haskell" is "strict Haskell". is it really a Haskell or is it a different language altogether? – Will Ness May 04 '20 at 21:09
  • @WillNess sorry, you're right, I was thinking of reference vs value. I'd not actually come across "call by name" before. – Robin Zigmond May 04 '20 at 21:15
  • Surely this is a homework problem – luqui May 04 '20 at 21:29

2 Answers2

3

"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.

Will Ness
  • 62,652
  • 8
  • 86
  • 167
0

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.

Sereja Bogolubov
  • 2,996
  • 2
  • 9
  • 22