【问题标题】:Why (apply and '(1 2 3)) doesn't work while (and 1 2 3) works in R5RS? [duplicate]为什么 (apply and '(1 2 3)) 不起作用,而 (and 1 2 3) 在 R5RS 中起作用? [复制]
【发布时间】:2013-06-18 09:47:12
【问题描述】:

我在 Racket 中这样尝试过

> (apply and '(1 2 3))
. and: bad syntax in: and
> (and 1 2 3)
3

有人对此有想法吗?

【问题讨论】:

  • 因为and 是宏,而不是函数。
  • 如果问题是重复的,但答案似乎添加了其他信息,那么有没有办法将两个问题混合在一起?

标签: lisp scheme


【解决方案1】:

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))))

【讨论】:

    【解决方案2】:

    Chris Jester-Young 的answer 是对的,但我还想强调另一点。标准的and 运算符是一个宏,它通过(基本上,如果不完全)将(and a b c) 转换为(if a (if b c #f) #f),来延迟对其参数的评估。这意味着如果 a 为 false,则 bc 不会被评估。

    我们还可以选择定义and-function,以便(and-function a b c) 评估abc,并在值全部为真时返回真。这意味着所有abc 都会得到评估。 and-function 有一个很好的属性,你可以将它作为函数传递,因为它是一个函数。

    似乎仍然缺少一个选项:and-function-delaying-evaluation 当且仅当abc 都返回 true 时返回 return,但这不会评估,例如 @ 987654341@ 和 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 中,这可能是一个使用 Promise 的机会。)

    【讨论】:

    • @ChrisJester-Young 感谢您的编辑!我知道我提到过翻译,但我从来没有考虑过。现在发布它更符合问题。谢谢!
    猜你喜欢
    • 2021-05-07
    • 2019-01-09
    • 2023-01-16
    • 2018-10-27
    • 1970-01-01
    • 2017-07-10
    • 2019-09-26
    • 2021-03-23
    相关资源
    最近更新 更多