6

For the following code:

(foldl and #t '(#t #f))

Racket returns:

and: bad syntax in: and

I know and is not a function. And I can circumvent this problem using lambda:

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

I have 2 questions here:

  1. and is not a function. Then what is it? Is it a macro?

  2. My solution using lambda seems ugly. Is there a better way to solve this problem?

Thank you.

Ben
  • 3,612
  • 3
  • 19
  • 24
  • You can always prettify it with srfi-26 (cut) – daniel gratzer Jul 29 '13 at 09:40
  • 1
    @jozefg you mean `(foldl (cut and <> <>) #t '(#t #f))`? But [SRFI-26](http://docs.racket-lang.org/srfi-std/srfi-26.html?q=cut#cut) also says that `(cut if <> 0 1)` is illegal because `if` is not "an expression in the sense of R5RS" - which would seem to make `and` illegal as well there. – Will Ness Jul 29 '13 at 11:04
  • @WillNess It tests fine for me with racket 5.3. Whether this is implementation specific or not I'm not sure – daniel gratzer Jul 29 '13 at 11:09
  • 2
    You might be interested in [one of my answers](http://stackoverflow.com/a/17234845/1281433) in another similar question (possibly a duplicate) that looks at some possible ways of getting `and`-like functions, both non-short circuiting (like the one you provided in the question) and short-circuiting. – Joshua Taylor Jul 29 '13 at 12:21
  • @jozefg That something works in one implementation does not mean that @WillNess is wrong. Since `and` is library syntax for `if` `(cut and ...)` is the same as `(cut if ...)`. Since the SRFI says it's illegal you can expect undefined behaviour and should avoid it. – Sylwester Jul 29 '13 at 15:44
  • @Sylwester That's why I said "I'm not sure if this is implementation specific" :) – daniel gratzer Jul 29 '13 at 15:50
  • @jozefg actually, SRFI-26 says `if` "not an expression in the sense of R5RS" and gives a link which defines the relevant `expr` case as `variable`, and defines `variable` as "not syntax", and also defines `and` as "syntax"; so in *Scheme* it *shouldn't* work. But Racket is not Scheme. :) – Will Ness Jul 29 '13 at 17:41
  • @Sylwester btw in SO only the first `@` designation fires up a notification; any others are ignored. :) – Will Ness Jul 29 '13 at 17:42
  • @jozefg `(begin (define x "hello") (string-set! x 0 #\H) x)` evaluates to "Hello" in most implementations. A R6RS **should** raise &assertion exception, but like R5RS it doesn't have to. Only when the report writes "an exception is raised" do they really have to. By not demanding anything in an implementation the responsibility is pushed to the developer not to write such violating, bad code like `(cut and <> <>)` because it might evaluate to 'hazy. @WillNess I'll keep it in mind :) – Sylwester Jul 29 '13 at 19:57
  • 1
    @Sylwester I'm aware of what undefined behavior is, I acknowledged that it was possible that it was UB, it was merely an observation. You're completely right, I just wasn't aware that it was ub and made an observation based on that. – daniel gratzer Jul 29 '13 at 19:59
  • @jozefg BTW we really need `(lambda (a b) (and b a))`, so the `cut` just won't cut it here. :) But thanks for bringing it up and thus triggering a discussion. :) – Will Ness Jul 30 '13 at 06:35

1 Answers1

8

It is a conditional syntactic form, or it might be implemented as a macro that expands to some core syntax form, which is treated as a special case by the compiler/interpreter.

The list there in Racket's docs includes if as a special form but doesn't include and, so the latter most probably is implemented in terms of the former. But R5RS does list and as a syntactic keyword. So, best we can say, it's either a special syntax, or a macro.

It is easy to re-write any and form (and a b c ...) as an if form, (if a (if b (if c #t #f) #f) #f).

lambda is fine by me, but you can also use every from SRFI-1 (or Racket's andmap):

(every identity '(#t #f))

should return #f.

edit: except, as Joshua Taylor points out, calling your lambda through a function like foldl does not short-circuit. Which defeats the purpose to calling the and in the first place.

Another thing is, in Racket's foldl the last argument to lambda is the one that receives the previous result in the chain of applications; so the implementation should really be

(foldl (lambda (a b) (and b a)) #t '(#t #f))
Community
  • 1
  • 1
Will Ness
  • 70,110
  • 9
  • 98
  • 181