【问题标题】:Java style FOR loop in a clojure interpeter?clojure 解释器中的 Java 样式 FOR 循环?
【发布时间】:2011-01-07 19:29:36
【问题描述】:

我有一个 clojure 的基本解释器。现在我需要实现

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)))

【问题讨论】:

  • 你想做什么?在 clojure 中创建 for 循环或在 clojure 中为您自己的自定义语言创建解释器?
  • 不是您特定问题的答案(不确定它是什么),但请查看多方法。他们应该很好地摆脱你所拥有的那种单一的条件。

标签: java clojure for-loop scheme interpreter


【解决方案1】:

我不完全确定您的解释语言的语法是什么,但看起来您已经实现了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这样的糖。

祝你好运!

【讨论】:

  • 在 Clojure 中,lambda 是 fn。
  • 我知道,但是在 OP 的解释语言中,关键字是 lambda。上面所有的扩展代码都将被解释,它们都不是 Clojure 的。
【解决方案2】:

您可能已经发现,clojure 没有 for(尽管您可以实现一个)循环。您只需像这样使用简单的递归调用:

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

只要您的finish-test 计算结果为false,recur 就会使用update-var 的值作为新的var 将执行返回到loop 的开头。见http://clojure.org/functional_programming

【讨论】:

猜你喜欢
  • 1970-01-01
  • 2013-08-17
  • 2023-04-10
  • 2010-11-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-08-20
  • 2023-01-07
相关资源
最近更新 更多