Scheme 报价单和清单有什么区别?

Scheme 报价单和清单有什么区别?,scheme,racket,evaluation,quote,Scheme,Racket,Evaluation,Quote,我知道您可以使用”(又称quote)创建列表,我一直都在使用它,如下所示: > (car '(1 2 3)) 1 > (quote (quote 3)) (quote 3) (define impostor-quote (syntax-rules () ((_ (a . b)) (cons (impostor-quote a) (impostor-quote b))) ((_ (e ...)) (list (impostor-quote e) ...))

我知道您可以使用
(又称
quote
)创建列表,我一直都在使用它,如下所示:

> (car '(1 2 3))
1
> (quote (quote 3))
(quote 3)
(define impostor-quote
  (syntax-rules ()
    ((_ (a . b)) (cons (impostor-quote a) (impostor-quote b)))
    ((_ (e ...)) (list (impostor-quote e) ...))
    ((_ x)       x)))
但它并不总是像我期望的那样工作。例如,我尝试创建一个函数列表,如下所示,但没有成功:

> (define math-fns '(+ - * /))
> (map (lambda (fn) (fn 1)) math-fns)
application: not a procedure;
  expected a procedure that can be applied to arguments
  given: '+
当我使用
列表
时,它可以工作:

> (define math-fns (list + - * /))
> (map (lambda (fn) (fn 1)) math-fns)
'(1 -1 1 1)
为什么??我认为
只是一个方便的速记,那么为什么行为会有所不同呢?

TL;博士:他们是不同的;如有疑问,请使用
列表
。 经验法则:只要你想计算参数,就使用
list
<代码>引用在其参数上“分布”,因此
'(+12)
类似于
(列表'+'1'2)
。您将在列表中得到一个符号,而不是一个函数


深入查看
列表
报价
在Scheme和Racket中,
quote
list
是完全不同的东西,但由于它们都可以用来生成列表,所以混淆是常见的,也是可以理解的。它们之间有一个极其重要的区别:
列表
是一个普通的函数,而
引用
(即使没有特殊的
语法)是一种特殊形式。也就是说,
list
可以在普通方案中实现,但是
quote
不能

列表
功能
list
函数实际上是这两个函数中最简单的一个,所以让我们从这里开始。它是一个接受任意数量参数的函数,它将参数收集到一个列表中

> (list 1 2 3)
(1 2 3)
上面的例子可能会让人困惑,因为结果被打印为
引号
able s表达式,这是真的,在本例中,这两个语法是等价的。但如果我们稍微复杂一点,你会发现它是不同的:

> (list 1 (+ 1 1) (+ 1 1 1))
(1 2 3)
> '(1 (+ 1 1) (+ 1 1 1))
(1 (+ 1 1) (+ 1 1 1))
quote
示例中发生了什么?好的,我们稍后会讨论这个问题,但首先,请看一下
列表
。它只是一个普通函数,因此遵循标准的Scheme求值语义:它在将每个参数传递给函数之前求值。这意味着像
(+1 1)
这样的表达式在被收集到列表中之前将被缩减为
2

向列表函数提供变量时,此行为也可见:

> (define x 42)
> (list x)
(42)
> '(x)
(x)
使用
list
x
在传递到
list
之前进行评估。有了
quote
,事情就更复杂了

最后,因为
list
只是一个函数,所以它可以像其他函数一样使用,包括以高阶方式使用。例如,可以将其传递给
map
函数,它将正常工作:

> (map list '(1 2 3) '(4 5 6))
((1 4) (2 5) (3 6))
报价
表格 与列表不同,引号是Lisps的一个特殊部分。
quote
表单之所以特别,部分原因是它有一个特殊的读者缩写,
,但即使没有这个缩写,它也很特别。与
list
不同,
quote
不是一个函数,因此它不需要像有自己规则的函数那样运行

浅谈Lisp源代码 在Lisp中,Scheme和Racket都是派生的,所有代码实际上都是由普通的数据结构组成的。例如,考虑下面的表达式:

(+ 1 2)
该表达式实际上是一个列表,它有三个元素:

  • +
    符号
  • 编号
    1
  • 号码
    2
所有这些值都是程序员可以创建的正常值。创建
1
值非常容易,因为它会自行计算:您只需键入
1
。但是符号和列表更难:默认情况下,源代码中的符号执行变量查找!也就是说,符号不是自评估的:

但事实证明,符号基本上只是字符串,事实上我们可以在它们之间进行转换:

> (string->symbol "a")
a
列表甚至比符号做得更多,因为默认情况下,源代码中的列表调用函数!执行
(+1 2)
查看列表中的第一个元素
+
符号,查找与其关联的函数,并与列表中的其余元素一起调用它

不过,有时您可能希望禁用这种“特殊”行为。您可能希望只获取列表或符号,而不对其求值。为此,您可以使用
quote

引语的意义 考虑到所有这些,很明显,
quote
的作用是:它只是“关闭”它所包装的表达式的特殊求值行为。例如,考虑<代码>引用<代码> ING符号:

> (quote a)
a

同样,考虑<代码>引用<代码>列表:

> (quote (a b c))
(a b c)
不管你给了什么,它总是,总是,总是,把它吐出来。不多也不少。这意味着,如果您给它一个列表,所有的子表达式都不会被计算——不要期望它们会被计算!如果需要任何类型的评估,请使用
list

现在,有人可能会问:如果你引用符号或列表以外的东西,会发生什么?答案是。。。没有什么!你只要把它拿回来

> (quote 1)
1
> (quote "abcd")
"abcd"
这是有道理的,因为
quote
仍然会准确地说出你给它的东西。这就是为什么像数字和字符串这样的“文字”在Lisp术语中有时被称为“自引用”的原因

还有一件事:如果
quote
表达式包含
quote
,会发生什么?也就是说,如果您“双重
报价”

> (quote (quote 3))
'3
那里发生了什么事?好吧,记住,
实际上只是
quote
的直接缩写,所以没有什么特别的事情发生!事实上,如果您的方案在打印时有一种禁用缩写的方法,它将如下所示:

> (car '(1 2 3))
1
> (quote (quote 3))
(quote 3)
(define impostor-quote
  (syntax-rules ()
    ((_ (a . b)) (cons (impostor-quote a) (impostor-quote b)))
    ((_ (e ...)) (list (impostor-quote e) ...))
    ((_ x)       x)))
不要被特别的东西所愚弄:就像
> (quasiquote (1 2 (+ 1 2)))
(1 2 (+ 1 2))
> (quasiquote (1 2 (unquote (+ 1 2))))
(1 2 3)
> (define x 42)
> (quasiquote (x is: (unquote x)))
(x is: 42)
> `(x is: ,x)
(x is: 42)
(define (list . args)
  args)
(define fake-quote
  (syntax-rules ()
    ((_ arg) arg)))
(define impostor-quote
  (syntax-rules ()
    ((_ (a . b)) (cons (impostor-quote a) (impostor-quote b)))
    ((_ (e ...)) (list (impostor-quote e) ...))
    ((_ x)       x)))
> (list 1 2 3)
'(1 2 3)
[1]> (mapcar (lambda (f) (funcall f 1)) '(+ - * /))
(1 -1 1 1)
(list '+ '- '* '/)
expected a procedure that can be applied to arguments
given: '+