Java-цикл FOR в стиле clojure? - PullRequest
       25

Java-цикл FOR в стиле clojure?

2 голосов
/ 07 января 2011

У меня есть основной переводчик в 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)))

Ответы [ 2 ]

0 голосов
/ 08 января 2011

Я не был полностью уверен, каков синтаксис вашего интерпретируемого языка, но похоже, что вы реализовали lambda, и это все, что вам действительно нужно, чтобы получить много синтаксического сахара. Вы можете реализовать такие вещи, как for циклы, используя lambda.

Все, что вам действительно нужно сделать, это добавить функцию 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 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 заставляет все выражение выполняться сразу.

Если вам нужны более подробные сведения об этом, в превосходной Структуре и интерпретации компьютерных программ есть глава , посвященная созданию мета-циклических интерпретаторов, и обсуждаются вопросы реализации внутренних определений, а также они называют «производные выражения», которые в основном сахар, как for.

Удачи!

0 голосов
/ 07 января 2011

Как вы, возможно, обнаружили, у clojure нет циклов for (хотя вы могли бы реализовать один). Вы просто используете простой рекурсивный вызов, подобный этому:

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

Пока ваш finish-test оценивается как false, recur вернет выполнение к началу loop, используя значение update-var в качестве нового var. Смотри http://clojure.org/functional_programming

...