GNU Emacs 32.0.50 (9008bf64c3) のマニュアルを PLaMo 翻訳で機械翻訳したものです。誤訳を含むことがあります。原文: https://www.gnu.org/software/emacs/manual/html_node/elisp/Deferred-Eval.html ・ emacs-doc.conao3.com

10.6 遅延評価とレイジー評価

式の評価を遅延させることが有用な場合があります。例えば、プログラムの後続処理で結果が不要であることが判明した場合に、時間のかかる計算の実行を避けたい場合などが挙げられます。thunk ライブラリでは、このような遅延評価をサポートするために、以下の関数とマクロを提供しています。

マクロ: thunk-delay forms…

forms を評価するための サンク を返します。サンクとは、thunk-delay の呼び出しのレキシカル環境を継承するクロージャ(クロージャ を参照)のことです。このマクロを使用するには lexical-binding が必要です。

関数: thunk-force thunk

thunk を強制し、thunk を生成した thunk-delay で指定されたフォームの評価を行わせます。最後のフォームの評価結果が返されます。また、thunk は自身が強制されたことを「記憶」しており、同じ thunk を用いて thunk-force をさらに呼び出しても、フォームを再評価することなく同じ結果が返されるだけとなります。

マクロ: thunk-let (bindings…) forms…

このマクロは let と同様ですが、「遅延」変数バインディングを生成します。任意のバインディングは (symbol value-form) という形式をとります。let とは異なり、任意の value-form の評価は、forms の評価時に対応する symbol のバインディングが初めて使用されるまで延期されます。任意の value-form は最大で1回のみ評価されます。このマクロを使用するには lexical-binding が必要です。

例:

(defun f (number)
  (thunk-let ((derived-number
              (progn (message "Calculating 1 plus 2 times %d" number)
                     (1+ (* 2 number)))))
    (if (> number 10)
        derived-number
      number)))

(f 5)
⇒ 5

(f 12)
⊣ Calculating 1 plus 2 times 12
⇒ 25

lazily bound 変数はその特殊な性質から、これらに値を代入すること(例:setq)はエラーとなります。

マクロ: thunk-let* (bindings…) forms…

これは thunk-let と同様ですが、bindings 内の任意の式は、この thunk-let* 形式における先行する束縛を参照できます。このマクロを使用するには lexical-binding が必要です。

(thunk-let* ((x (prog2 (message "Calculating x...")
                    (+ 1 1)
                  (message "Finished calculating x")))
             (y (prog2 (message "Calculating y...")
                    (+ x 1)
                  (message "Finished calculating y")))
             (z (prog2 (message "Calculating z...")
                    (+ y 1)
                  (message "Finished calculating z")))
             (a (prog2 (message "Calculating a...")
                    (+ z 1)
                  (message "Finished calculating a"))))
  (* z x))

⊣ Calculating z...
⊣ Calculating y...
⊣ Calculating x...
⊣ Finished calculating x
⊣ Finished calculating y
⊣ Finished calculating z
⇒ 8

thunk-let と thunk-let* は暗黙的にサンクを使用します。これらの展開によってヘルパーシンボルが生成され、それらが束縛式をラップするサンクにバインドされます。その後、本体 forms 内の元の変数へのすべての参照が、対応するヘルパー変数を引数として thunk-force を呼び出す式に置き換えられます。したがって、thunk-let や thunk-let* を使用するコードはすべてサンクを使うように書き換えることが可能ですが、多くの場合、これらのマクロを使用した方が、サンクを明示的に使用するよりも洗練されたコードになります。