Reputation: 957
I'm working on a homework assignment where we are asked to implement an evaluation strategy called "call by name" in a certain language that we developed (using Scheme).
We were given an example in Scala, but I don't understand how "call by name" works and how it is different to "call by need"?
Upvotes: 21
Views: 34892
Reputation: 932
An important aspect of call-by-name is that, yes, the parameter is evaluated every single time it is come across during the callee's execution, but it is evaluated IN THE CALLER'S SCOPE, not the scope where the parameter is evaluated.
This is important to understand because variables in the caller's scope can change during the callee's execution meaning that the parameter's evaluation can lead to different values during the execution of the calle's execution.
Upvotes: 0
Reputation: 121
Call-by-name strategy does not evaluate arguments of the function until using them.
Example of call-by-name steps in Scala:
def square(a: Int) = a * a
// (b: => Int, c: => Int means that Scala will evaluate b and c with call-by-name startegy
def sumSquare(b: => Int, c: => Int ): Int = square(b) + square(c)
sumSquare(2, 3+3)
square(2) + square(3+3)
2 * 2 + square(3+3)
4 + square(3+3)
4 + (3+3) * (3+3) // duplicate evaluation
4 + 9 * (3+3)
4 + 9 * 9
85
Call-by-name can produce duplicates of evaluations. Also, the side effects of this strategy are less predictable. That's why the default Scala strategy is call-by-value.
You can read about the call-by-name strategy and the difference between call-by-value strategy here:
https://www.scaler.com/topics/call-by-name/
Call-by-need strategy, also known as a lazy evaluation strategy, evaluates an expression the first time it called, and uses a dictionary to keep the result of the evaluation for a specific expression.
More about lazy evaluation (call-by-need) here:
https://medium.com/background-thread/what-is-lazy-evaluation-programming-word-of-the-day-8a6f4410053f
Upvotes: 0
Reputation: 27164
Add this to the above answers:
Work through the SICP section on Streams. It gives a good explanation of both call-by-name and call-by-need. It also shows how to implement those in Scheme. BTW, if you are looking for a quick solution here is a basic call-by-need implemented in Scheme:
;; Returns a promise to execute a computation. (implements call-by-name)
;; Caches the result (memoization) of the computation on its first evaluation
;; and returns that value on subsequent calls. (implements call-by-need)
(define-syntax delay
(syntax-rules ()
((_ (expr ...))
(let ((proc (lambda () (expr ...)))
(already-evaluated #f)
(result null))
(lambda ()
(if (not already-evaluated)
(begin
(display "computing ...") (newline)
(set! result (proc))
(set! already-evaluated #t)))
result)))))
;; Forces the evaluation of a delayed computation created by 'delay'.
(define (my-force proc) (proc))
A sample run:
> (define lazy (delay (+ 3 4)))
> (force lazy)
computing ... ;; Computes 3 + 4 and memoizes the result.
7
> (my-force lazy)
7 ;; Returns the memoized value.
Upvotes: 3
Reputation: 19965
Call by name is a a parameter passing scheme where the parameter is evaluated when it is used, not when the function is called. Here's an example in pseudo-C:
int i;
char array[3] = { 0, 1, 2 };
i = 0;
f(a[i]);
int f(int j)
{
int k = j; // k = 0
i = 2; // modify global i
k = j; // The argument expression (a[i]) is re-evaluated, giving 2.
}
The argument expression is lazily evaluated when accessed using the current values of the argument expression.
Upvotes: 19
Reputation: 41170
Call-by-need is a memoized version of call-by-name (see wikipedia).
In call-by-name, the argument is evaluated every time it is used, whereas in call-by-need, it is evaluated the first time it is used, and the value recorded so that subsequently it need not be re-evaluated.
Upvotes: 31