I'm not much of a Python guy, but that chained comparison operator is sweet!
Sure, it's just syntax sugar, but it saves a lot of keystrokes, especially if the variable name is long.
Is Python the only language with this feature?
Sure, it's just syntax sugar, but it saves a lot of keystrokes, especially if the variable name is long.
Is Python the only language with this feature?
(< a b c d) ;; T if a < b < c < d
(<= a b c d) ;; T if a < b < c < d
Also: (lcm a b c d ...) ;; lowest common multiple
(+) -> 0
(+ a) -> a
(+ a b) -> a + b
(+ a b c) -> (a + b) + c
(*) -> 1
(* a) -> a
(* a b) -> a * b
(* a b c) -> (a * b) * c
Is it just syntactic sugar? (< a b c) evaluates a, b and c only once, which matters if they are expensive external function calls or have side effects. (and (< (foo) (bar))
(< (bar) (baz)))
isn't the same as (< (foo) (bar) (baz))
By the way, this could be turned into a short-circuiting operator: more semantic variation. Suppose < is allowed to control evaluation. Then an expression like (< a b c d) could avoid evaluating the c and d terms, if the a < b comparison fails. a < b >= c
?Obviously, you can express it slightly more verbosely:
(and (< a b) (>= 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 comma (<= 1 2 2 5 6 6 9)
and for making = actually useful (works on nested structures properly)."Is this sorted", and "are these equal" are intuitive and useful concepts in programming and you shouldn't need to reimplement them each time you need them.
def sideEffects():
print "Called."
return 5
if 0 < sideEffects() < 10:
# sideEffects is only called onceNo. See, e.g., http://stackoverflow.com/questions/4090845/language-support-...
if 2 > 3 and 2 < 7
becomes
if 3 < 2 < 7
> perl6
> 3 < 4 < 5
TrueWhat does 5 > 4 > 3 give?