secd in clojure

clojure でも secd machine を書いてみようとやってみて、あまりに clojure について知らなすぎることが分かった。

  • (cons 1 2) はエラー。(cons 1 (list 2)) は OK
  • car, cdr はfirst,rest
  • begin, progn のかわりに do
  • cond,let は lisp に比べてカッコが一つ少ない。
  • clojure-mode.el (ちょっと古いかもしれないが)は、C-c C-l (clojure-load-file) でいちいち repl バッファをポップアップする。バッファを分割してソースと repl にしておくと、C-c C-l で両方が repl バッファになってしまう。うっとうしいので closure-load-file 関数の switch-to-lisp をとりあえずコメントアウトした。

まだ途中だけど一応張っておく。

(defn car
  [lst]
  (first lst))

(defn cdr
  [lst]
  (rest lst))

(defn cadr
  [lst]
  (car (cdr lst)))

(defn cddr
  [lst]
  (cdr (cdr lst)))

(defn locate
  [i j env]
  (nth (nth env (- i 1)) (- j 1)))

(defn secd "SECD Machine"
  [s e c d]
  (if (empty? c)
    (list s e c d)
    (let [c0 (first c)
          cs (rest c)]
      (println (list s e c d))
      (cond
       ;; A. Push Objects to Stack
       (= c0 'NIL) (recur (cons 'NIL s) e cs d)
       (= c0 'LDC) (recur (cons (cadr c) s) e (rest cs) d)
       ;;(= c0 'LD) (recur (cons (locate i j e) s) e (rest c d)
       ;; B. Built-in Functions
       ;; Unary operator OP:
       (= c0 '+) (recur (cons (+ (car s) (cadr s)) (cddr s)) e cs d)
       (= c0 '-) (recur (cons (- (car s) (cadr s)) (cddr s)) e cs d)
       ;; C. The Special function IF_THEN_ELSE
       (= c0 'SEL) (do
                     (if (car s)
                       (recur (cdr s) e (car cs) (cons (cddr cs) d))
                       (recur (cdr s) e (cadr cs) (cons (cddr cs) d))))
       :else
       (recur s e cs d)))))

多分続く。