kiyokaのブログアーカイブ

Archive of old blog posts

ついにorとandを定義できた

私がRubyで書いているLisp方言、 [Nendo]の開発状況続き。

macroで構文をどんどん定義している。 ついに or と and が定義できた。ついでに let1 も。 先日定義したcondも使っている。すごい勢いで積み上がっていく感じが楽しいぞ。 img

(define let1
  (macro (var expr body)
    (list 'let (list (list var expr)) body)))
(define or
  (macro lst
    (define (or_iter lst)
      (cond
       ((eq? 0 (length lst))
        false)
       ((eq? 1 (length lst))
        (let1 sym (gensym)
              (list 'let1 sym (car lst)
                    (list 'if sym sym false))))
       (else
        (let1 sym (gensym)
              (list 'let1 sym (car lst)
                    (list 'if sym sym (or_iter (cdr lst))))))))
    (or_iter lst)))
(define and
  (macro lst
    (define (and_iter lst)
      (cond
       ((eq? 0 (length lst))
        true)
       ((eq? 1 (length lst))
        (car lst))
       (else
        (list 'if (list 'not (list 'eq? 'false (car lst)))
              (and_iter (cdr lst))
              'false))))
    (and_iter lst)))

これが実行結果

bash-3.2$ ./nendo
nendo> (or)
false
nendo> (or 1 2 3)
1
nendo> (or false false 3)
3
nendo> (and)
true
nendo> (and true)
true
nendo> (and 1 2 3)
3
nendo> (and false 2) 
false
nendo> (and true  2)
2
nendo> (and 1 2 (print "3\n") (print "4\n") 5)
3
4
5
nendo> (and 1 2 false (print "3\n") (print "4\n") 5)
false

実は、gensym関数の実装はかなりサボっているのだ。 gensymで生成されるシンボルは若干ぶつかりにくいネーミングルールになっているだけ。いつかイタイ目に会うのかな。

nendo> (macroexpand '(or 1 2))
(let ((__gensym__10 1)) (if __gensym__10 __gensym__10 (let ((__gensym__11 2)) (if __gensym__11 __gensym__11 false))))

このへんがToy言語っぽい。何とかしたい…