我像这样在球拍中尝试过
> (apply and '(1 2 3))
. and: bad syntax in: and
> (and 1 2 3)
3
有人对此有想法吗?
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))))
Chris Jester-Young 的回答是正确的,但我还想强调另一点。标准and
运算符是一个宏,它通过(基本上,如果不完全)(and a b c)
变成(if a (if b c #f) #f)
. 这意味着 ifa
为假,b
并且c
不被评估。
我们还可以定义一个and-function
这样的选项,它(and-function a b c)
计算a
、b
和c
,并在值都为真时返回真。这意味着所有a
、b
和c
都得到评估。 and-function
有一个很好的属性,你可以将它作为函数传递,因为它是一个函数。
似乎仍然缺少一个选项:and-function-delaying-evaluation
当且仅当a
,b
和c
全部返回 true 时返回 return 的一个选项,但它不评估,例如,b
如果c
产生a
false。实际上,这可以通过一个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
您只需要通过将事物包装在函数中并让-like 函数调用这些函数来产生值来延迟评估。(在 Scheme 中,这可能是一个使用 Promise 的机会。)