19

为什么以下不起作用?

(apply and (list #t #t #f))

虽然以下工作正常。

(apply + (list 1 3 2))

R5RS 和 R6RS 似乎都是这种情况?

4

9 回答 9

14

and不是一个正常的函数,因为它只会根据需要评估尽可能少的参数,以了解结果是真还是假。例如,如果第一个参数为假,那么无论其他参数是什么,结果都必须为假,因此它不会评估其他参数。如果and是一个普通函数,它的所有参数都将首先被评估,所以and被设为一个特殊的关键字,这就是它不能作为变量传递的原因。

于 2008-12-22T23:49:02.713 回答
6
(define and-l (lambda x 
    (if (null? x)
        #t
        (if (car x) (apply and-l (cdr x)) #f))))

请注意这是 lambda variadic!应用示例(and-l #t #t #f)

或者您可以通过应用程序(如要求)使用它,例如(apply and-l (list #t #t #f))

两个选项都可以...

于 2011-07-17T23:46:15.530 回答
5

and实际上是一个宏,其定义在 R5RS 第 4 章中有概述。该页面上的符号“库语法”实际上意味着它是作为宏实现的。

7.3 节,派生表达式类型给出了and宏的可能定义:

(define-syntax and
  (syntax-rules ()
    ((and) #t)
    ((and test) test)
    ((and test1 test2 ...)
     (if test1 (and test2 ...) #f))))

鉴于此定义,不可能将其and用作apply.

于 2008-12-23T00:38:18.743 回答
3

在 Scheme 方言MIT/GNU Scheme中,您可以使用函数boolean/and而不是特殊形式and

(apply boolean/and (list #t #t #f)) ;Value: #f

另外,作为记录,我在Guile Scheme过程索引中找不到任何等效函数。

(其他答案已经解释了为什么特殊形式and不起作用,并展示了如果您的方言中还没有这样的函数,如何编写自己的替换函数。)

于 2013-01-24T13:23:54.213 回答
1

如果你真的想要一个函数指针指向一个函数,并且你不介意与“真实”不同的行为,那么这将起作用:

(define and-l (lambda (a b) (and a b)))

您可以像这样申请:

(apply and-l (list #t #f))

两个警告是:

  1. 所有的 args 都被评估,违反了 and 的定义,应该有快捷行为。
  2. 只允许两个参数。
于 2009-02-02T14:08:31.913 回答
1

我偶然发现了同样的问题,并在 Racket 中找到了一个优雅的解决方案。由于问题在于“and”是一个宏而不是一个函数,以防止对其所有参数进行评估,我读了一些关于“lazy racket”的文章,发现“and”是语言中的一个函数。所以我想出了以下解决方案,我只是将惰性导入为“惰性和”:

#lang racket
(require (only-in lazy [and lazy-and]))

(define (mm)
  (map number? '(1 2 3)))

(printf "~a -> ~a\n" (mm) (apply lazy-and (mm)))

产生

(#t #t #t) -> #t
于 2012-05-09T16:16:50.887 回答
0

试试这个:

(define list-and (lambda (args) (and (car args) (list-and (cdr args)))))

那么你可以使用apply to list-and!

于 2010-02-07T03:57:11.197 回答
0

你也可以使用

(define (andApply lBoo) (if (not (car lBoo)) #f (if (= 1(length lBoo)) (car lBoo) (andApply (cdr lBoo)))))

于 2014-06-14T19:54:38.077 回答
-1

我在使用 PLT-Scheme 372 时也遇到了这个问题,我已经深入研究了 and-syntax 的行为,并找出了下面的代码,它的工作原理就好像人们直觉地期望(apply and lst)返回一样,但我没有做过详尽的测试.

(define (list-and lst) 
  (cond 
    ((null? lst) '())
    ((not (pair? lst)) (and lst)) 
    ((eq? (length lst) 1) (car lst))
    (else
     (and (car lst)
          (list-and (cdr lst))))
    )
  )

Welcome to DrScheme, version 372 [3m].
Language: Textual (MzScheme, includes R5RS).

> (eq? (and '()) (list-and '()))
#t
> (eq? (and '#f) (list-and (list '#f)))
#t
> (eq? (and 'a) (list-and (list 'a)))
#t
> (eq? (and 'a 'b) (list-and (list 'a 'b)))
#t
> (eq? (and 'a 'b '()) (list-and (list 'a 'b '())))
#t
> (eq? (and 'a 'b '#t) (list-and (list 'a 'b '#t)))
#t
> (eq? (and 'a 'b '#f) (list-and (list 'a 'b '#f)))
#t

我还想出了另一个令人费解的解决方法。我称它为心灵陷阱,因为一开始我不知道如何将它变成一个函数......这里是(只是我直观想法的演示):

Welcome to DrScheme, version 372 [3m].
Language: Textual (MzScheme, includes R5RS).
> (eval (cons 'and (list ''#f ''#f ''#t)))
#f
> (eval (cons 'and (list ''a ''b ''c)))
c

但是后来我问了一个问题,在这里得到了答案:是否可以动态生成 (quote (quote var)) 或 ''var?. 有了这个答案,人们可​​以很容易地将上述想法变成一个函数。

(define (my-quote lst)
  (map (lambda (x) `'',x) lst))

(cons 'and (my-quote (list 'a 'b 'c)))
=> '(and ''a ''b ''c)
于 2013-12-26T07:22:52.053 回答