But can any lisp dialect do:
a < b >= c
? a < b >= c
? (rel a < b >= c)
evaluates a, b, c once, left to right, and then performs the comparisons between the successive evaluated terms. $ cat rel.lisp
(defmacro rel (&rest args)
(loop for expr in args by #'cddr
for g = (gensym)
collect g into gens
collect `(,g ,expr) into lets
finally (return `(let ,lets
(and
,(loop for (left op right) on args by #'cddr
for (lgen rgen) on gens
while rgen
collect `(,op ,lgen ,rgen)))))))
$ clisp -q -i rel.lisp
;; Loading file rel.lisp ...
;; Loaded file rel.lisp
[1]> (macroexpand '(rel))
(LET NIL (AND NIL)) ;
T
[2]> (macroexpand '(rel x))
(LET ((#:G3219 X)) (AND NIL)) ;
T
[3]> (macroexpand '(rel x < y))
(LET ((#:G3220 X) (#:G3221 Y)) (AND ((< #:G3220 #:G3221)))) ;
T
[4]> (macroexpand '(rel x < y >= z))
(LET ((#:G3222 X) (#:G3223 Y) (#:G3224 Z))
(AND ((< #:G3222 #:G3223) (>= #:G3223 #:G3224)))) ;
T
[5]> (macroexpand '(rel x < y >= z < w))
(LET ((#:G3225 X) (#:G3226 Y) (#:G3227 Z) (#:G3228 W))
(AND ((< #:G3225 #:G3226) (>= #:G3226 #:G3227) (< #:G3227 #:G3228)))) ;
T
Could use some error checking, obviously, to make it a production-quality macro. (AND ((...) (...) ...)))
should be (AND (...) (...) ...)
I haven't run the generated code once, yet I can debug it: such is the power of the HN development environment.The fix, of course, is to splice the comparison expressions into the AND:
`(let ,lets
(and
,@(loop for ... ))) ; comma splat, not commaObviously, you can express it slightly more verbosely:
(and (< a b) (>= b c))