Почему (применять и "(1 2 3)) не работает, пока (и 1 2 3) работает в R5RS?

Я попробовал это в Racket, как это

> (apply and '(1 2 3))
. and: bad syntax in: and
> (and 1 2 3)
3

Есть ли у кого-нибудь идеи об этом?

Ответ 1

Chris Jester-Young ответ прав, но есть еще один момент, который я хочу выделить. Стандартный and оператор - это макрос, который задерживает оценку его аргументов, (по существу, если не точно), превращая (and a b c) в (if a (if b c #f) #f). Это означает, что если a false, b и c не оцениваются.

У нас также есть возможность определить and-function, так что (and-function a b c) оценивает a, b и c и возвращает true, когда значения являются истинными. Это означает, что все a, b и c получают оценку. and-function имеет приятное свойство, что вы можете передать его как функцию, потому что это функция.

Есть еще один параметр, который, кажется, отсутствует: a and-function-delaying-evaluation, который возвращает return тогда и только тогда, когда a, b и c все возвращают true, но это не оценивает, например, b и c, если a создает ложь. Это может быть фактически реализовано с помощью функции and-funcalling-function, которая требует, чтобы ее аргументы были списком функций. Например:

(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

Используя макрос и эту идиому, мы можем реально реализовать что-то со стандартной семантикой and:

(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))))

Урок, который нужно убрать из этого, конечно, состоит в том, что вы можете иметь and -подобную функцию, которую вы можете пройти и все еще получать отложенную оценку; вам просто нужно отложить оценку, обернув вещи в функции и позволяя and -подобной функции вызывать эти функции для создания значений. (В схеме это может быть возможность использовать promises.)

Ответ 2

and не является функцией, это макрос, поэтому вы не можете передавать его как функцию.

Причиной and является макрос, чтобы включить поведение короткого замыкания. Вы можете сделать свою собственную версию без короткого замыкания:

(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)))))

и my-and могут использоваться с apply.

Для сравнения, здесь макрос (который делает короткое замыкание) выглядит так:

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