Reputation: 50017
I'm trying to translate the Common Lisp code in the original "Calendrical Calculations" paper by Derhowitz and Reingold to Clojure. In this paper there is a macro named sum
which is given in Common Lisp as
(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))))
and which I've translated to Clojure as
(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))))
However, when I use the above in a function (for example, the following)
(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.
I get an error similar to the following:
CompilerException java.lang.RuntimeException: Unable to resolve
symbol: G__53 in this context, compiling:(NO_SOURCE_PATH:165:8)
I'm almost completely unfamiliar with the Lisp/Clojure macro system, but from what I can determine it's saying that the gensym
invocation in the let
block has created a symbol (in this case G__53
) which is being invoked, but which doesn't exist. That makes sense, but I suspect it's not the intent of the original code - however, I don't know much about Common Lisp and thus I'm not able to figure out A) what the original CL code is trying to do here, and B) how to produce a Clojure equivalent to this.
For what it's worth - the Clojure version of the other functions used in absolute-from-gregorian
are:
(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)))
Any and all pointers as to how to make this work greatly appreciated.
Upvotes: 1
Views: 202
Reputation: 5395
This can be expressed with a loop
construct in Clojure:
(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#)))
Example:
(sum (* x x) x 1 (<= x 3)) ;; => 14
Note also that it may be sufficient to use Clojure's standard constructs instead of custom macros. As an example, the line in the code with the calendar calculations can be rewritten as:
(reduce + (map #(last-day-of-gregorian-month % year) (range 1 month)))
Upvotes: 3
Reputation: 91857
do
in common lisp doesn't act anything like do
in clojure. You'll have to look up what do
actually does (it's a looping construct in common lisp, and a grouping construct in clojure), and figure out how to accomplish the same thing.
Upvotes: 4