Я попробовал это в Racket, как это
> (apply and '(1 2 3))
. and: bad syntax in: and
> (and 1 2 3)
3
Есть ли у кого-нибудь идеи об этом?
Я попробовал это в Racket, как это
> (apply and '(1 2 3))
. and: bad syntax in: and
> (and 1 2 3)
3
Есть ли у кого-нибудь идеи об этом?
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.)
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))))