2016-12-04 56 views
1

我在尝试将Common Lisp代码the original "Calendrical Calculations" paper by Derhowitz and Reingold翻译为Clojure。在本文中有一个名为sum这是Common Lisp中给出将宏从Common Lisp翻译为Clojure

(defmacro sum (expression index initial condition) 
;; sum expession for index = initial and successive integers, 
;; as long as condition holds. 
(let* ((temp (gensym))) 
    `(do ((,temp 0 (+ ,temp ,expression)) 
     (,index ,initial (i+ ,index))) 
     ((not ,condition) ,temp)))) 

和我已经翻译成Clojure的作为

(defmacro sum [expression index initial condition] 
    ; sum expession for index = initial and successive integers, 
    ; as long as condition holds. 
    (let [temp (gensym)] 
    `(do ((~temp 0 (+ ~temp ~expression)) 
      (~index ~initial (inc ~index))) 
     ((not ~condition) ~temp)))) 

然而,宏当我使用上面的函数(例如,以下同)

(defn absolute-from-gregorian [date] 
    ;; Absolute date equivalent to the Gregorian date. 
    (let [month (extract-month date) 
     year (extract-year date)] 
    ; Return 
    (+ (extract-day date)   ;; Days so far this month. 
     (sum       ;; Days in prior months this year. 
     (last-day-of-gregorian-month m year) m 1 (< m month)) 
     (* 365 (dec year))   ;; Days in prior years. 
     (quotient (dec year) 4)  ;; Julian leap days in prior years... 
     (-       ;; ... minus prior century years... 
     (quotient (dec year) 100)) 
     (quotient     ;; ...plus prior years divisible... 
     (dec year) 400))))   ;; ... by 400. 

我得到类似如下的错误:

CompilerException java.lang.RuntimeException: Unable to resolve 
    symbol: G__53 in this context, compiling:(NO_SOURCE_PATH:165:8) 

我与Lisp的/ Clojure的宏系统几乎完全陌生的,但是从我可以确定它说,gensym调用在let块创建了一个符号(在这种情况下G__53),其上调用,但这不存在。 是有道理的,但我怀疑它不是原始代码的意图 - 但是,我对Common Lisp不太了解,因此我无法弄清楚A)原始CL代码试图做什么在这里,和B)如何产生一个与此相当的Clojure。

对于它的价值 - 在absolute-from-gregorian使用的其他功能Clojure的版本是:

(defn quotient [m n] 
    (int (Math/floor (/ m n)))) 

(defn extract-month [date] 
    (first date)) 

(defn extract-day [date] 
    (second date)) 

(defn extract-year [date] 
    (second (rest date))) 

任何和所有的指针就如何使这项工作十分赞赏。

回答

3

这可以用Clojure中的一个loop结构来表示:

(defmacro sum [expression index initial condition] 
    ; sum expession for index = initial and successive integers, 
    ; as long as condition holds. 
    `(loop [~index ~initial temp# 0] 
    (if ~condition 
     (recur (inc ~index) (+ temp# ~expression)) 
     temp#))) 

例子:

(sum (* x x) x 1 (<= x 3)) ;; => 14 

还请注意,这可能是足够使用Clojure的标准结构,而不是自定义宏。例如,带日历计算代码中的行可以被重写为:

(reduce + (map #(last-day-of-gregorian-month % year) (range 1 month))) 
+0

非常感谢。在发布我的问题后,我继续处理这个问题,并确定使用'recur'的循环是合适的,但对Clojure/Lisp宏还不太了解,我还没有弄清楚如何将它们放在一起。看起来我必须拿起[关于Clojure宏的书](https://pragprog.com/book/cjclojure/mastering-clojure-macros),花些时间学习更多关于它们的知识。 –

4

do in common lisp在clojure中没有像do这样的行为。你将不得不查看do实际上做了什么(它是一个普通的lisp中的循环构造,以及clojure中的一个分组构造),并找出如何完成同样的事情。