tags:

views:

768

answers:

4

Why doesn't the following work?

(apply and (list #t #t #f))

While the following works just fine.

(apply + (list 1 3 2))

This seems to be the case in both R5RS and R6RS?

+4  A: 

and isn't a normal function because it will only evaluate as few arguments as it needs, to know whether the result is true or false. For example, if the first argument is false, then no matter what the other arguments are, the result has to be false so it won't evaluate the other arguments. If and were a normal function, all of its arguments would be evaluated first, so and was made a special keyword which is why it cannot be passed as a variable.

yjerem
This is one of my greatest frustrations with Scheme - macros should be first-class. I realize that it may prevent some compilation optimization, but it would definitely increase the expressive power of the language.
Kyle Cronin
+2  A: 

and is actually a macro, whose definition is outlined in R5RS chapter 4. The notation "library syntax" on that page really means it is implemented as a macro.

Section 7.3, Derived expression types gives a possible definition of the and macro:

(define-syntax and
  (syntax-rules ()
    ((and) #t)
    ((and test) test)
    ((and test1 test2 ...)
     (if test1 (and test2 ...) #f))))

Given this defintion, it is not possible to use and as a function argument to apply.

Greg Hewgill
A: 

If you REALLY wanted to have a function pointer to a function that does and, and you don't mind behavior different than the "real" and, then this would work:

(define and-l (lambda (a b) (and a b)))

Which you can apply like this:

(apply and-l (list #t #f))

The two caveats are:

  1. All of the args get evaluated, in violation of the definition of and, which should have shortcutting behavior.
  2. Only two arguments are allowed.
Jeff Allen
`(define (and/f . xs) (cond ((null? xs) #t) ((null? (cdr xs)) (car xs)) (else (and (car xs) (apply and/f (cdr xs))))))`
Lajla
+1  A: 

try this:

(define list-and (lambda (args) (and (car args) (list-and (cdr args)))))

then you can use apply to list-and!

eitazhou
This will not work as expected. Try this instead: (define (list-and args) (if (null? args) #t (and (car args) (list-and (cdr args)))))
Stefan Kangas