11 ms·
But can any lisp dialect do: a < b >= c ?
by hasenj 12y ago
But can any lisp dialect do:
a < b >= c
?
- baddox 12y agoGiven that lisps tend to use prefix notation, the example doesn't even translate meaningfully.
- dllthomas 12y agoI assume the above was intended to be a Python expression. The answer, to the best of my knowledge, is "not really". There is no built in or reasonably standard function that lets you check simultaneously that a is less than b which in turn is greater than or equal to c. Not that we couldn't define one ad-hoc, although making it reusable in a way that's reasonably idiomatic might be a challenge... Obviously, you can express it slightly more verbosely: (and (< a b) (>= b c))
- davidrusu 12y ago(< a (>= b c)) same number of operators but a few extra parens
- deleted 12y ago[deleted]
- Jach 12y agoThis isn't the same thing -- the Python syntax is asking for a < b and b >= c, while only evaluating b once. There are many infix math libraries for lisps (e.g. this one from 1995: https://www.cs.cmu.edu/afs/cs/project/ai-repository/ai/lang/lisp/code/syntax/infix/infix.cl https://www.cs.cmu.edu/afs/cs/project/ai-repository/ai/lang/...) that allow things like #I(a < b >= c), but the trick is only evaluating b once. (The linked lib will expand into two evaluations if b is an expression.)
- kazinator 12y agoHere (>= b c) will return a boolean value, which you're then comparing to a.
- kazinator 12y agoWhich means it could be done, but the relational operators (any one of which could be the leftmost constituent) have to all be defined as macros which analyze the rest of the expression with alternative evaluation rules.
- kazinator 12y agoYes, for instance in Common Lisp we can make ourselves a rel macro, such that (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.
- kazinator 12y agoIn a Lisp-1 dialect like Scheme, rel could easily and conveniently be a function. The call (rel a < b <= c) simply evaluates its arguments. The arguments < and <= are functions. The rel function then just operates on these values.
- kazinator 12y agoAnyone spot the bug? Of course (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 comma