9

I was trying with the following code in racket and MIT scheme, surprise me that the compiler throw err

(foldr and #t '(#t #t #f))

Is there any way to use reduce/fold way to check if a list contains only true or false? I know a lambda can do the job, but it really make we wonder why this is not a valid code. I remember I can do it in Haskell.....

TIA.

user734736
  • 91
  • 1
  • 2

4 Answers4

9

and is a macro, so it doesn't have a value by itself. Specifically, it short-circuits evaluation, and using it as you tried to will not make any sense. For that reason, Racket has andmap which you can use in such cases. (Other implementations have similar functionality under different names -- for example, srfi-1 uses every.)

Eli Barzilay
  • 29,301
  • 3
  • 67
  • 110
  • Short-circuiting evaluation doesn't necessarily imply being unable to fold. The OP isn't asking for side-effects. If I `and` the initializing value and the first element, I should get either a true or false. `and`ing that with the second element should do the same, etc. – drysdam May 02 '11 at 17:18
  • No, it doesn't imply being unable to fold *if* you're willing to accept that `(and ...)` in a form and a standalone `and` have different semantics. The overwhelmingly popular choice was to avoid such confusion. Consider the fact that in any Scheme implementation that has identifier macros (Racket included) it is extremely easy to implement such a double-faced `and`, and that the issue is far from one that was never discussed. – Eli Barzilay May 02 '11 at 18:16
  • Then there's the other way out: (try to) have both `and` forms share the same semantics -- another well-hashed idea... On one side you get some surprises (either `foldl` becomes a special form, or you revert to the non-short-circuiting behavior), and on the more important side, you get to ... fexprs, and all the fun that that implies. – Eli Barzilay May 02 '11 at 18:20
  • Thanks for the replies! it really bother me a lot and I couldn't figure it out, but i got to say it really catch me that `and` is a macro. I really only have procedure/function in my mind while testing.... still new to scheme – user734736 May 03 '11 at 13:32
8

And is a macro and can not be used as a function. Put it in a function:

(foldr (lambda (a b) (and a b)) #t '(#t #t #f))

knivil
  • 916
  • 5
  • 10
2

This works in guile:

(primitive-eval (cons 'and '(#t #f)))
drysdam
  • 8,341
  • 1
  • 20
  • 23
  • That works in many implementations (in Racket you'd use `eval`), but it's a bad idea for other reasons. (Eg, either you swallow the surprise that `(let ((x 1)) (eval (cons 'and '(x))))` doesn't work, or you avoid such things which leaves you with `andmap`/`every` -like functionality.) – Eli Barzilay May 02 '11 at 18:26
  • Surely if I built up the list *as a string* and then evaluated the string it would work. I thought the whole point of lisp was that program and data are the same stuff. – drysdam May 02 '11 at 18:34
  • No, evaluating code from a string has the exact same issues. What I meant by avoiding them is avoiding any references to bindings -- and that leaves you with the plain ability to reduce a list of values in the same way `andmap` does. – Eli Barzilay May 02 '11 at 23:00
1

One thing that might be off is that in Racket and Scheme, true values are anything other than #f. Since your question asks for booleans, the following will be more discriminating:

#lang racket
(define (boolean-true? x) (eq? x #t))
(define (only-contains-#t? l)
  (andmap boolean-true? l))

For example,

> (only-contains-#t? '())
#t
> (only-contains-#t? '(#t #t #t))
#t
> (only-contains-#t? '(#t #t true))
#f
dyoo
  • 11,795
  • 1
  • 34
  • 44