私は、私たちが開発した特定の言語 (Scheme を使用) で「名前による呼び出し」と呼ばれる評価戦略を実装するように求められる宿題に取り組んでいます。
Scala で例を挙げましたが、「名前による呼び出し」がどのように機能し、「必要に応じて呼び出す」とどのように違うのかわかりませんか?
私は、私たちが開発した特定の言語 (Scheme を使用) で「名前による呼び出し」と呼ばれる評価戦略を実装するように求められる宿題に取り組んでいます。
Scala で例を挙げましたが、「名前による呼び出し」がどのように機能し、「必要に応じて呼び出す」とどのように違うのかわかりませんか?
Call-by-need は、call-by-name のメモ化されたバージョンです ( wikipediaを参照)。
名前による呼び出しでは、引数は使用されるたびに評価されますが、必要による呼び出しでは、最初に使用されたときに評価され、値が記録されるため、後で再評価する必要はありません。
名前による呼び出しは、関数が呼び出されたときではなく、使用されたときにパラメーターが評価されるパラメーター受け渡しスキームです。疑似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.
}
引数式の現在の値を使用してアクセスすると、引数式は遅延評価されます。
これを上記の回答に追加します。
StreamsのSICP セクションに取り組みます。これは、名前による呼び出しと必要による呼び出しの両方について適切に説明しています。また、Scheme でそれらを実装する方法も示します。ところで、簡単な解決策を探している場合は、Scheme で実装された基本的な call-by-need を次に示します。
;; 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))
サンプル実行:
> (define lazy (delay (+ 3 4)))
> (force lazy)
computing ... ;; Computes 3 + 4 and memoizes the result.
7
> (my-force lazy)
7 ;; Returns the memoized value.