Lispのオペレータは関数とマクロに大別できる

REPループについての説明で言ったように、Lispにコンピュータ的な処理をさせるには、要素をカッコで囲んだリストを入力してやります。

(OPERATOR arg1 arg2 ...)

そのリストの最初の要素には普通、オペレータ(を表すシンボル)がきます。

処理系が、このオペレータに渡す引数の扱いのちがいで、オペレータは関数とマクロに大別できます。

関数
すべての引数を一度、評価(eval)してから、関数本体に渡す。
KISS>(+ 10 *pi*)
;; シンボル+が表す関数本体には、
;; 引数として 10を評価した結果 10 と
;; 定数*pi*を評価した結果 0.3141592653589793e1 が渡される

0.13141592653589793e2 ;; 10 + 3.14 = 13.14

KISS>
KISS>(* (+ 10 *pi*) 3)
;; 最初に、掛け算をする関数*への引数がすべて評価される
;;
;; 一つ目の引数 (+ 10 *pi*) を評価すると上記のように値
;; 0.13141592653589793e2 が得られる。
;;
;; 二つ目の引数 3 は評価しても 3 のまま
;;
;; したがって、関数*の本体は、引数として
;; 0.13141592653589793e2 と 3 を受け取り、
;; 掛け算をして結果を返す

0.39424777960769379e2
;; 3.14 + 10 で 13.14 、13.14 * 3 = 39.42
KISS>

定義用オペレータ(defining operator)であるdefunを使ってユーザは関数を定義できます。

マクロ
すべての引数を、そのまま、マクロ本体に渡す。

なぜ、マクロがあるかと言うと、if, whileなどのような構文をユーザが自由に定義できるようにするためです。
たとえば、if構文は以下のような見た目をしています。

(if test-form then-form [else-form])

あるLisp Objectを評価(eval)されるものとして見るとき、それをフォーム(form)と呼びます。

KISS>(if (> 10 0) 'plus 'minus-or-zero)

plus

;; test-formである(> 10 0)を評価すると真(t)なので
;; then-form である'plus が評価されplusが返された
;; else-form である'minus-or-zero は一度も評価されないまま

KISS>

私が実装中のISLisp処理系KISSでは、スペシャルオペレータ if は次のように実装されています。
スペシャルオペレータは、あらかじめ用意されたオペレータで、引数の扱いから見るとマクロのように見えます。

/* special operator: (if test-form then-form [else-form]) -> <object> */
kiss_obj* kiss_if(kiss_obj* test_form, kiss_obj* then_form, kiss_obj* rest) 
{
  //test_form を評価(kiss_eval)した結果が KISS_NIL か
    //どうかで、then_form か rest の
    //どちらか一方だけが、
    //評価(kiss_eval)される
    if (kiss_eval(test_form) != KISS_NIL) {
	return kiss_eval(then_form);
    } else {
	return kiss_eval_body(rest);
    }
}

定義用オペレータ(defining operator)であるdefmacroを使ってユーザはマクロを定義できますが、どの引数が評価されるかは、自由に決められます。




コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です