我在这样的Racket中尝试过它
> (apply and '(1 2 3))
. and: bad syntax in: and
> (and 1 2 3)
3
有没有人有这方面的想法?
答案 0 :(得分:10)
Chris Jester-Young的answer是对的,但还有一点我想强调一点。标准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
,并在值为0时返回true都是真的。这意味着评估了所有a
,b
和c
。 and-function
有一个很好的属性,你可以将它作为函数传递,因为它是一个函数。
还有一个选项似乎缺失:只有当and-function-delaying-evaluation
,a
和b
都返回true时,c
才会返回返回如果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
- 像函数调用这些函数来生成值。 (在Scheme中,这可能是使用promises的机会。)
答案 1 :(得分:8)
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))))