(define (try a b) (if (= a 0) 1 b))を考えよう. (try 0 (/ 1 0))の評価はSchemeではエラーになる. 遅延評価ではエラーにならない. 引数(/ 1 0)は決して評価されず, 評価は1を返す.
遅延評価を利用する一つの例は, 手続きunlessの定義である.
(define (unless condition usual-value exceptional-value) (if condition exceptional-value usual-value))は
(unless (= b 0) (/ a b) (begin (display "exception: returning 0") 0))のような式で使うことが出来る. 通常の値と例外の値の両方がunlessが呼び出される前に評価されるので, 作用的順序の言語では使うことが出来ない(問題1.6と比較せよ). 遅延評価の利点は, unlessのようなある種の手続きに, 引数の評価でエラーになったり, 停止しないものがあっても, 有用な計算が出来ることである.
引数が評価される前に手続きの本体に入る時, その手続きはその引数について ノンストリクト(non-strict)であるという. 手続きの本体に入る前に引数が評価される時, その手続きはその引数について ストリクト(strict)であるという. 33 純粋に作用的順序の言語では, すべての手続きは各引数につき, ストリクトである. 純粋に正規的順序の言語では, すべての合成手続きは各引数につきノンストリクトであり, 基本手続きはストリクトかノンストリクトかのいずれかである. また言語によっては(問題4.31参照)自分で定義した手続きのストリクトさにつき, 細かい制御をプログラマに与えるものもある.
ノンストリクトにするのが有用な手続きの劇的な例はcons(あるいは一般にデータ構造の構成子の殆んど)である.
要素の値が分らなくても, 要素を組み合せてデータ構造を作り, 結果のデータ構造に演算して有用な計算をすることが出来る. 例えばリストの中の個々の要素の値を知らずとも, リストの長さを計算するというのは十分意味あることである. この考えは4.2.3節で使い, 3章のストリームをノンストリクトなconsの対で作ったリストとして実装する.
問題 4.25
(通常の作用的順序のSchemeで)unlessを上に示したように定義したとし,
factorialをunlessを使って
(define (factorial n) (unless (= n 1) (* n (factorial (- n 1))) 1))と定義したとする. (factorial 5)を評価しようとすると何が起きるか. われわれの定義は正規順序の言語では動くだろうか.
32
「遅延」の用語と「正規順序」の用語の違いは曖昧である. 一般に「遅延」は特定の評価器の機構を指し, 「正規順序」は特定の評価戦略とは無関係に, 言語の意味論を指す. しかしこれも不動の区別ではなく, 二つの用語はよく取り替えて使われる.
33
「ストリクト」と「ノンストリクト」の用語は本質的に「作用的順序」と「正規順序」と同じ意味であるが, この用語は言語全体に関してではなく, 個々の手続きと引数について述べる点が違う. プログラム言語の学会で誰かが「正規順序の言語
Hassleにはいくつかのストリクトな基本手続きがある, その他の手続きはその引数を遅延評価でとる」と発言するのを聞くかも知れない.