3
$\begingroup$

SML uses pass‑by‑value, Haskell uses call‑by‑need. Unless I'm wrong (the purpose of this question), one can do call‑by‑need with SML, passing a function instead of a value; a function to be later evaluated when needed.

Adapting a classical example:

(* This will print `0` *)

fun pass_by_function (cond, a1, a2) =
   if cond then a1
   else a2

val e1 = fn () => 1 * 0
val e2 = fn () => 1 div 0

val _ = print (Int.toString (pass_by_function (true, e1, e2) ()))

(* This will fail with a divide error *)

fun pass_by_value (cond, a1, a2) =
   if cond then a1
   else a2

val _ = print (Int.toString (pass_by_value (true, 1 * 0, 1 div 0)))

It's a big matter for Haskell to be call‑by‑need. I'm just wondering if there is something else or if it's just, say “syntactic sugar”, compared to the way it needs to be done with SML.

Is this just a different way to write the same or is there a semantic difference I'm not aware of? Passing a function, is it indeed always the same as call‑by‑need? If not, when and how does it differs?

$\endgroup$
1
  • 1
    $\begingroup$ It's syntactic sugar, as far as I know. Always have to use this transformation in SML would be a pain and would make the code less transparent (harder to read). $\endgroup$
    – D.W.
    Jul 21, 2014 at 22:45

1 Answer 1

6
$\begingroup$

Call-by-need is more than call-by-name. Call-by-name is syntactic sugar for wrapping a closure (thunk) around each argument and then passing the pointer to the closure. Your example shows what call-by-name turns into under the covers.

Call-by-need goes one step further by memoizing. If an argument is used twice in a function then the thunk corresponding to that argument is only evaluated once, the result is stored, and then on the second (and after) use of that argument the stored value is returned instead of paying the cost of reevaluating the function.

This only works because Haskell is pure functional. That means that every function call always returns the same result for the same inputs. With a language with any mutation you can't make this guarantee, so it is much harder to do call-by-need automatically. SML allows mutation.

$\endgroup$
4
  • $\begingroup$ Is memoization required for a proper call‑by‑need or this an option Haskell provides? $\endgroup$
    – Hibou57
    Jul 22, 2014 at 0:42
  • 1
    $\begingroup$ The definition of call-by-need is call-by-name with memoization. Haskell specifies call-by-need because call-by-name can be much more expensive than call-by-value (because if you have a parameter that you use more than once then call-by-name evaluates that parameter more than once while call-by-value (and call-by-need) evaluate the parameter exactly once.) $\endgroup$ Jul 22, 2014 at 1:59
  • $\begingroup$ OK. I'm confused between call by name and by value (I've removed the reference to call by name in the starting post). So whether good or bad, there is a difference, which is the memoization. I'm selecting this answer. $\endgroup$
    – Hibou57
    Jul 22, 2014 at 2:15
  • $\begingroup$ I found another source which confirms your words: Evaluation and Call-by-value, call-by-name and call-by-need. This confirms call‑by‑need implies memoization. $\endgroup$
    – Hibou57
    Jul 22, 2014 at 12:03

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.