我在这样的Racket中试过它
> (apply and '(1 2 3))
. and: bad syntax in: and
> (and 1 2 3)
3
Run Code Online (Sandbox Code Playgroud)
有没有人有这个想法?
Jos*_*lor 10
Chris Jester-Young的答案是正确的,但还有一点我想强调一点.标准的and
操作是延缓了它的参数评估,由(基本上,如果不完全)转向宏(and a b c)
成(if a (if b c #f) #f)
.这意味着,如果a
是假的,b
并c
没有得到评估.
我们也有定义的选项and-function
,使得(and-function a b c)
求值a
,b
和c
,当值全部为真,则返回true.这意味着所有的a
,b
以及c
得到评估. and-function
有一个很好的属性,你可以传递它作为函数,因为它是一个函数.
还是有一个选项,似乎缺少:一个and-function-delaying-evaluation
是返回的回报,当且仅当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
Run Code Online (Sandbox Code Playgroud)
使用宏和这个习惯用法,我们实际上可以用标准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))))
Run Code Online (Sandbox Code Playgroud)
当然,从中学到的教训是,你可以拥有一个and
类似的功能,你可以传递并仍然得到延迟评估; 你只需要通过在函数中包装东西来延迟评估,让and
-like函数调用这些函数来产生值.(在Scheme中,这可能是使用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)))))
Run Code Online (Sandbox Code Playgroud)
并my-and
可以使用apply
.
为了比较,这是宏(它做短路)的样子:
(define-syntax and
(syntax-rules ()
((and) #t)
((and test) test)
((and test rest ...) (if test
(and rest ...)
#f))))
Run Code Online (Sandbox Code Playgroud)