I tried it in Racket like this
> (apply and '(1 2 3))
. and: bad syntax in: and
> (and 1 2 3)
3
Does anyone have ideas about this?
I tried it in Racket like this
> (apply and '(1 2 3))
. and: bad syntax in: and
> (and 1 2 3)
3
Does anyone have ideas about this?
Chris Jester-Young's answer is right, but there's one other point I want to highlight. The standard and
operator is a macro which delays the evaluation of its arguments, by (essentially, if not exactly) turning (and a b c)
into (if a (if b c #f) #f)
. This means that if a
is false, b
and c
do not get evaluated.
We also have the option of defining an and-function
such that (and-function a b c)
evaluates a
, b
, and c
, and returns true when the values are all true. This means that all of a
, b
, and c
get evaluated. and-function
has the nice property that you can pass it around as function because it is a function.
There's still one option that seems to be missing: an and-function-delaying-evaluation
that returns return if and only if a
, b
, and c
all return true, but that doesn't evaluate, e.g., b
and c
if a
produces false. This can be had, actually, with a function and-funcalling-function
that requires its arguments to be a list of functions. For instance:
(define (and-funcalling-function functions)
(or (null? functions)
(and ((car functions))
(and-funcalling-function (cdr functions)))))
(and-funcalling-function
(list (lambda () (even? 2))
(lambda () (odd? 3))))
; => #t
(and-funcalling-function
(list (lambda () (odd? 2))
(lambda () (even? 3)))) ; (even? 3) does not get evaluated
; => #f
Using a macro and this idiom, we can actually implement something with the standard and
semantics:
(define-syntax standard-and
(syntax-rules ()
((standard-and form ...)
(and-funcalling-function (list (lambda () form) ...)))))
(macroexpand '(standard-and (odd? 2) (even? 3)))
; =>
; (and-funcalling-function
; (list (lambda () (odd? 2))
; (lambda () (even? 3))))
The lesson to take away from this, of course, is that you can have an and
-like function that you can pass around and still get delayed evaluation; you just need to delay evaluation by wrapping things in functions and letting the and
-like function call those functions to produce values. (In Scheme, this might be an opportunity to use promises.)
and
is not a function, it's a macro, so you cannot pass it around like a function.
The reason and
is a macro, is to enable short-circuiting behaviour. You can make your own non-short-circuiting version:
(define (my-and . items)
(if (null? items) #t
(let loop ((test (car items))
(rest (cdr items)))
(cond ((null? rest) test)
(test (loop (car rest) (cdr rest)))
(else #f)))))
and my-and
can be used with apply
.
For comparison, here's what the macro (which does do short-circuiting) looks like:
(define-syntax and
(syntax-rules ()
((and) #t)
((and test) test)
((and test rest ...) (if test
(and rest ...)
#f))))