btw0
btw0

Reputation: 3626

Using AND with the apply function in Scheme

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?

Upvotes: 19

Views: 10327

Answers (9)

Rory O'Kane
Rory O'Kane

Reputation: 30388

In the Scheme dialect MIT/GNU Scheme, you can use the function boolean/and instead of the special form and.

(apply boolean/and (list #t #t #f)) ;Value: #f

Also, for the record, I couldn’t find any equivalent function in Guile Scheme’s procedure index.

(Other answers have already explained why the special form and won’t work, and shown how to write your own replacement function if there isn’t already such a function in your dialect.)

Upvotes: 3

Pages0
Pages0

Reputation: 1

You could also use

(define (andApply lBoo) (if (not (car lBoo)) #f (if (= 1(length lBoo)) (car lBoo) (andApply (cdr lBoo)))))

Upvotes: 0

pimgeek
pimgeek

Reputation: 259

I also bump into this problem playing with PLT-Scheme 372, I have digged into the behavior of and-syntax, and figure out the follow code which works just as if one would intuitively expect (apply and lst) to return, but I haven't done exaustive test.

(define (list-and lst) 
  (cond 
    ((null? lst) '())
    ((not (pair? lst)) (and lst)) 
    ((eq? (length lst) 1) (car lst))
    (else
     (and (car lst)
          (list-and (cdr lst))))
    )
  )

Welcome to DrScheme, version 372 [3m].
Language: Textual (MzScheme, includes R5RS).

> (eq? (and '()) (list-and '()))
#t
> (eq? (and '#f) (list-and (list '#f)))
#t
> (eq? (and 'a) (list-and (list 'a)))
#t
> (eq? (and 'a 'b) (list-and (list 'a 'b)))
#t
> (eq? (and 'a 'b '()) (list-and (list 'a 'b '())))
#t
> (eq? (and 'a 'b '#t) (list-and (list 'a 'b '#t)))
#t
> (eq? (and 'a 'b '#f) (list-and (list 'a 'b '#f)))
#t

I've also figured out another mind-trapping workaround. I call it mind-trapping because at first I don't know how to turn it into a function... Here it is (only a demo of my intuitive idea):

Welcome to DrScheme, version 372 [3m].
Language: Textual (MzScheme, includes R5RS).
> (eval (cons 'and (list ''#f ''#f ''#t)))
#f
> (eval (cons 'and (list ''a ''b ''c)))
c

But later I asked a question and got the answer here: Is it possible to generate (quote (quote var)) or ''var dynamically? . With this answer one can easily turn the above idea into a function.

(define (my-quote lst)
  (map (lambda (x) `'',x) lst))

(cons 'and (my-quote (list 'a 'b 'c)))
=> '(and ''a ''b ''c)

Upvotes: -1

uselpa
uselpa

Reputation: 18917

I've stumbled across the same problem and found an elegant solution in Racket. Since the problem is that "and" is a macro and not a function in order to prevent the evaluation of all its arguments, I've read a little on "lazy racket" and found that "and" is a function in that language. So I came up with the following solution where I just import the lazy and as "lazy-and":

#lang racket
(require (only-in lazy [and lazy-and]))

(define (mm)
  (map number? '(1 2 3)))

(printf "~a -> ~a\n" (mm) (apply lazy-and (mm)))

which yields

(#t #t #t) -> #t

Upvotes: 1

Alex v
Alex v

Reputation: 69

(define and-l (lambda x 
    (if (null? x)
        #t
        (if (car x) (apply and-l (cdr x)) #f))))

pleas notice that this is lambda variadic! apply example (and-l #t #t #f)

or you can use it via apply procedure(as was asked) for example (apply and-l (list #t #t #f))

both options are ok...

Upvotes: 6

eitazhou
eitazhou

Reputation: 9

try this:

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

then you can use apply to list-and!

Upvotes: 0

Jeff Allen
Jeff Allen

Reputation: 1471

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.

Upvotes: 1

Greg Hewgill
Greg Hewgill

Reputation: 992945

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.

Upvotes: 5

Paige Ruten
Paige Ruten

Reputation: 176645

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.

Upvotes: 15

Related Questions