为什么(申请和'(1 2 3))不起作用,而(和1 2 3)在R5RS中有效?

Han*_*Sun 3 lisp scheme

我在这样的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是假的,bc没有得到评估.

我们也有定义的选项and-function,使得(and-function a b c)求值a,bc,当值全部为真,则返回true.这意味着所有的a,b以及c得到评估. and-function有一个很好的属性,你可以传递它作为函数,因为它是一个函数.

还是有一个选项,似乎缺少:一个and-function-delaying-evaluation是返回的回报,当且仅当a,bc所有返回true,但不评估,例如,bc如果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的机会.)


Chr*_*ung 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)))))
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)