2011-01-07 65 views
2

我在clojure有一個基本的解釋器。現在我需要執行Java風格FOR clojure interpeter循環?

for (initialisation; finish-test; loop-update) { 
statements 
} 

在我的解釋器裏面。我將附上我迄今爲止獲得的解釋器代碼。任何幫助表示讚賞。

解釋

(declare interpret make-env) ;; 

(def do-trace false) ;; 

;; simple utilities 

(def third ; return third item in a list 
(fn [a-list] 
    (second (rest a-list)))) 

(def fourth ; return fourth item in a list 
(fn [a-list] 
    (third (rest a-list)))) 

(def run ; make it easy to test the interpreter 
(fn [e] 
    (println "Processing: " e) 
    (println "=> " (interpret e (make-env))))) 

;; for the environment 

(def make-env 
    (fn [] 
    '())) 

(def add-var 
    (fn [env var val] 
    (cons (list var val) env))) 

(def lookup-var 
    (fn [env var] 
    (cond (empty? env) 'error 
      (= (first (first env)) var) (second (first env)) 
      :else (lookup-var (rest env) var)))) 

;; -- define numbers 

(def is-number? 
(fn [expn] 
    (number? expn))) 

(def interpret-number 
(fn [expn env] 
    expn)) 

;; -- define symbols 

(def is-symbol? 
    (fn [expn] 
    (symbol? expn))) 

(def interpret-symbol 
    (fn [expn env] 
    (lookup-var env expn))) 

;; -- define boolean 

(def is-boolean? 
    (fn [expn] 
    (or 
     (= expn 'true) 
     (= expn 'false)))) 

(def interpret-boolean 
    (fn [expn env] 
    expn)) 

;; -- define functions 

(def is-function? 
    (fn [expn] 
    (and 
     (list? expn) 
     (= 3 (count expn)) 
     (= 'lambda (first expn))))) 

(def interpret-function 
    (fn [expn env] 
    expn)) 

;; -- define addition 

(def is-plus? 
(fn [expn] 
    (and 
    (list? expn) 
    (= 3 (count expn)) 
    (= '+ (first expn))))) 

(def interpret-plus 
(fn [expn env] 
    (+ 
    (interpret (second expn) env) 
    (interpret (third expn) env)))) 

;; -- define subtraction 

(def is-minus? 
(fn [expn] 
    (and 
    (list? expn) 
    (= 3 (count expn)) 
    (= '- (first expn))))) 

(def interpret-minus 
(fn [expn env] 
    (- 
    (interpret (second expn) env) 
    (interpret (third expn) env)))) 

;; -- define multiplication 

(def is-times? 
(fn [expn] 
    (and 
    (list? expn) 
    (= 3 (count expn)) 
    (= '* (first expn))))) 

(def interpret-times 
(fn [expn env] 
    (* 
    (interpret (second expn) env) 
    (interpret (third expn) env)))) 

;; -- define division 

(def is-divides? 
(fn [expn] 
    (and 
    (list? expn) 
    (= 3 (count expn)) 
    (= '/ (first expn))))) 

(def interpret-divides 
(fn [expn env] 
    (/ 
    (interpret (second expn) env) 
    (interpret (third expn) env)))) 

;; -- define equals test 

(def is-equals? 
    (fn [expn] 
    (and 
     (list? expn) 
     (= 3 (count expn)) 
     (= '= (first expn))))) 

(def interpret-equals 
    (fn [expn env] 
    (= 
     (interpret (second expn) env) 
     (interpret (third expn) env)))) 

;; -- define greater-than test 

(def is-greater-than? 
    (fn [expn] 
    (and 
     (list? expn) 
     (= 3 (count expn)) 
     (= '> (first expn))))) 

(def interpret-greater-than 
    (fn [expn env] 
    (> 
     (interpret (second expn) env) 
     (interpret (third expn) env)))) 

;; -- define not 

(def is-not? 
    (fn [expn] 
    (and 
     (list? expn) 
     (= 2 (count expn)) 
     (= 'not (first expn))))) 

(def interpret-not 
    (fn [expn env] 
    (not 
     (interpret (second expn) env)))) 

;; -- define or 

(def is-or? 
    (fn [expn] 
    (and 
     (list? expn) 
     (= 3 (count expn)) 
     (= 'or (first expn))))) 

(def interpret-or 
    (fn [expn env] 
    (or 
     (interpret (second expn) env) 
     (interpret (third expn) env)))) 

;; -- define and 

(def is-and? 
    (fn [expn] 
    (and 
     (list? expn) 
     (= 3 (count expn)) 
     (= 'and (first expn))))) 

(def interpret-and 
    (fn [expn env] 
    (and 
     (interpret (second expn) env) 
     (interpret (third expn) env)))) 

;; -- define with 

(def is-with? 
    (fn [expn] 
    (and 
     (list? expn) 
     (= 3 (count expn)) 
     (= 'with (first expn))))) 

(def interpret-with 
    (fn [expn env] 
    (interpret (third expn) 
       (add-var env 
         (first (second expn)) 
         (interpret (second (second expn)) env))))) 

;; -- define if 

(def is-if? 
    (fn [expn] 
    (and 
     (list? expn) 
     (= 4 (count expn)) 
     (= 'if (first expn))))) 

(def interpret-if 
    (fn [expn env] 
    (cond (interpret (second expn) env) (interpret (third expn) env) 
      :else       (interpret (fourth expn) env)))) 

;; -- define function-application 

(def is-function-application? 
    (fn [expn env] 
    (and 
     (list? expn) 
     (= 2 (count expn)) 
     (is-function? (interpret (first expn) env))))) 

(def interpret-function-application 
    (fn [expn env] 
    (let [function (interpret (first expn) env)] 
     (interpret (third function) 
       (add-var env 
          (first (second function)) 
          (interpret (second expn) env)))))) 

;;解釋本身

(def interpret 
    (fn [expn env] 
    (cond do-trace (println "Interpret is processing: " expn)) 
    (cond 
     ; basic values 
     (is-number? expn) (interpret-number expn env) 
     (is-symbol? expn) (interpret-symbol expn env) 
     (is-boolean? expn) (interpret-boolean expn env) 
     (is-function? expn) (interpret-function expn env) 
     ; built-in functions 
     (is-plus? expn) (interpret-plus expn env) 
     (is-minus? expn) (interpret-minus expn env) 
     (is-times? expn) (interpret-times expn env) 
     (is-divides? expn) (interpret-divides expn env) 
     (is-equals? expn) (interpret-equals expn env) 
     (is-greater-than? expn) (interpret-greater-than expn env) 
     (is-not? expn) (interpret-not expn env) 
     (is-or? expn) (interpret-or expn env) 
     (is-and? expn) (interpret-and expn env) 
     ; special syntax 
     (is-with? expn) (interpret-with expn env) 
     (is-if? expn) (interpret-if expn env) 
     ; functions 
     (is-function-application? expn env) (interpret-function-application expn env) 
     :else 'error))) 
+2

你想做什麼?要在clojure中創建一個for循環或爲clojure創建一個用於您自己的定製語言的解釋器? – 2011-01-07 19:32:59

+2

不是你的具體問題的答案(不知道它是什麼),但檢查multimethods。他們應該做得很好,擺脫你那裏的那個龐然大物。 – Rayne 2011-01-07 19:36:52

回答

0

我不完全確定您的解釋型語言的語法是什麼,但看起來您已實施lambda這就是您真正需要獲取大量語法糖的所有內容。您可以使用lambda來實現諸如for循環之類的內容。

你真正需要做的是增加一個for-handler函數解析像一個表達式:

(for (i 0 (< 1 10)) 
    (print i)) 

到:

((lambda() 
    (define (loop i n) 
      (if (or (< i n) (= i n)) 
       (begin (print i) (loop (+ 1 i) n)))) 
    (loop 1 10))) 

,然後再通過這個新的表達式interpret。上面的代碼是從我解決了SICP Exercise 4.9

我並沒有花太多時間試圖找出如果你的解釋器支持這樣的內部定義,但它看起來像你有with這讓您可以像做這個:

(with (loop (lambda (i n) 
       (if (or (< i n) (= i n)) 
        (begin (print i) (loop (+ 1 i) n)))) 
     (loop 1 10)) 

本質上,您需要在遞歸函數的應用程序中擴展for表達式。上面的代碼定義了一個名爲loop的函數,並立即調用它。外部lambda強制整個表達式立即運行。

如果您想了解更多細節,關於構建元環解釋器的優秀Structure and Interpretation of Computer Programs有一章,並且討論了實施內部定義以及討論他們稱之爲「派生表達式」的內容,這些內容基本上是糖如for

祝你好運!

0

正如你可能已經發現,Clojure中不具有(雖然你可以實現一個)循環。你只需要使用這樣一個簡單的遞歸調用:

(loop [var inital-value] 
    ;; statements (regarding "var") 
    (when-not finish-test 
    (recur update-var))) 

只要你finish-test計算結果爲falserecur將恢復執行到loop使用update-var值作爲新var開始。請參閱http://clojure.org/functional_programming

+1

Clojure對** *宏*有一個**,http://clojure.github.com/clojure/clojure.core-api。html#clojure.core/for – Markc 2011-01-09 13:44:22