Schemeをつくろう(9) if

さて、構文という奴に取りかかります。あぁ、Schemeには構文がないんだっけ。でもifは構文だよな。マテ、値を返すから式か?・・・構文の定義がイマイチ微妙です。


あんまり細かいことは気にせず進みます。

ifの挙動

ifはdefineと同じように特別な関数です。

通常、Schemeは括弧の中から計算していく訳ですが、ifやdefineは括弧の中を評価するよりも先にやるべき事があります。

> (define l '(1 2 3))
> (if (pair? l)
      (car l)
      (cdr l))
1

実行の順番を整理すると、

  1. まず、(pair? l)を評価して、#t
  2. #tだったら、(car l)を評価。

この時、(cdr l)は評価しない。という所がポイント。だからifは特別な関数です。

実装

この考察を元に実装していきます。

#t,#fが無かったので、boolean型を増やしました。

実装はこんな感じ。

/* syntax */
static object if_syntax(object env, object args)
{
    if (length(args) == 3) {
        object ex = car(args);                 /* over write ex */

        ex = eval(env, ex);
        env = car(ex);                         /* split env */
        ex = cdr(ex);

        if (!is_boolean(ex))
            error("syntax if : not boolean");

        if (is_true(ex))
            return eval(env, cadr(args));
        else
            return eval(env, car(cddr(args)));
    } else
        error("syntax if : arugument error");
}

リスト処理系を増やしてみました。car,cdrを減らしていかないと。

evalすると、carに環境、cdrに結果が入って返ってきます。多値がホシィ。

てすとぉ

さて、遊んでみます。

input> (define b #f) (define x 5) (if b (+ x 2) (+ x 3))
debug> (define b #f)
#f
debug> (define x 5)
5
debug> (if b (+ x 2) (+ x 3))
8

おぉぉぉぉぉ。ifだぁ!!

電卓以上になった!!

ifを搭載したので、電卓以上の機能は備えたつもり。

(足し算しか出来ないけど)

環境問題

またここで環境の問題が・・・ifは環境を返すのかどうか?

debug> (if (define x #t) x y)
#t
debug> x
ERROR : eval : undefind value

ifの中では環境を維持するけど、外には出さないという方針で行きます。


言語デザインって大変なんだなぁと感じる。今日この頃です。