是什么报价和列表之间的区别?是什么报价和列表之间的区别?(What is the differenc

2019-05-11 15:33发布

我知道,你可以使用' (又名quote )创建列表,我用这一切的时候,是这样的:

> (car '(1 2 3))
1

但它并不总是工作像我期望。 例如,我试图创造的功能,像这样的列表,但它没有工作:

> (define math-fns '(+ - * /))
> (map (lambda (fn) (fn 1)) math-fns)
application: not a procedure;
  expected a procedure that can be applied to arguments
  given: '+

当我使用list ,它的工作原理:

> (define math-fns (list + - * /))
> (map (lambda (fn) (fn 1)) math-fns)
'(1 -1 1 1)

为什么? 我以为'只是一个方便的速记,那么为什么行为不同?

Answer 1:

TL; DR:他们是不同的; 使用list有疑问时。

经验法则:使用list时,你想要的参数进行评估; quote “分发”过它的参数,所以'(+ 1 2)是像(list '+ '1 '2) 你会在你的列表中的符号,而不是一个函数结束。


在深入看看listquote

在流程和球拍, quotelist完全不同的事情 ,但由于它们的可用于生产单,混乱是常见的,可以理解的。 它们之间有一个非常重要的区别: list是一个普通的旧功能 ,而quote (即使没有特殊的'语法)的一种特殊形式 。 也就是说, list可在普通的方案来实现,但quote是不可能的。

list功能

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

> (list 1 2 3)
(1 2 3)

上面的实例可以是混乱,因为结果被打印作为quote能够s表达式,它是真实的,在这种情况下,两种语法是等价的。 但是,如果我们稍微变得更加复杂,你会看到,这是不同的:

> (list 1 (+ 1 1) (+ 1 1 1))
(1 2 3)
> '(1 (+ 1 1) (+ 1 1 1))
(1 (+ 1 1) (+ 1 1 1))

这是怎么回事在quote的例子吗? 好了,我们将讨论在某一时刻,但首先,看看list 。 这只是一个普通的功能,因此它遵循标准方案评价语义:它评估每个参数他们得到传递给函数之前 。 这意味着,像表达式(+ 1 1)将减少至2它们会收集到列表中。

该列表功能提供的变量时,此行为也可见:

> (define x 42)
> (list x)
(42)
> '(x)
(x)

随着listx被获得通过之前评估list 。 随着quote ,事情更复杂。

最后,因为list只是一个功能,它可以用来就像任何其他的功能,包括高阶的方式。 例如,它可以被传递到map的功能,它会适当地工作:

> (map list '(1 2 3) '(4 5 6))
((1 4) (2 5) (3 6))

quote表格

报价单,不像list ,是的Lisp的一个特殊部分。 该quote的形式是在部分特殊的,因为它得到专门的阅读器的简称, ' ,但它也是特殊的,即使没有这一点。 不同于listquote 不是一个函数,因此它并不需要表现得像一个它有它自己的规则。

Lisp语言的源代码的一个简短的讨论

在Lisp,其方案和球拍是衍生物,所有代码实际上是由普通的数据结构。 例如,考虑以下表达式:

(+ 1 2)

那表情其实是一个列表 ,它有三个要素:

  • +符号
  • 1
  • 2

所有这些值是可以由程序员创建正常值。 这真的很容易造成1值,因为它的计算结果为自己:你只需要输入1 。 但是,符号和列表是更难:默认情况下,在源代码中的符号做一个变量查找! 也就是说,符号不是自我评价

> 1
1
> a
a: undefined
  cannot reference undefined identifier

事实证明,虽然符号基本上只是字符串,而事实上,我们可以将它们之间的转换:

> (string->symbol "a")
a

列出做多符号甚至更多,因为默认情况下,在源代码列表调用一个函数! 否则(+ 1 2)着眼于在列表中的第一元件,所述+符号,查找与它相关联的功能,并与在列表中的元素的其余部分调用它。

然而,有时候,你可能要禁用这个“特殊”的行为。 您可能希望只得到列表或得到符号,而它正在评估。 要做到这一点,你可以用quote

报价的含义

有了这一切记住,这是很明显什么quote的作用:它只是“关闭”了,它封装了表达的特殊评估行为。 例如,考虑quote荷兰国际集团的标志:

> (quote a)
a

同样,考虑quote荷兰国际集团的列表:

> (quote (a b c))
(a b c)

不管你所付出的quote ,它会一直, 一直吐回了你。 无多,不会少。 这意味着,如果你给它一个列表,这些子表达式进行评估,不要指望他们是! 如果您需要任何形式的评估,使用list

现在,有人可能会问:发生了什么,如果你quote比符号或列表中的其他东西吗? 那么,答案就是什么都没有! 你只要把它找回来。

> (quote 1)
1
> (quote "abcd")
"abcd"

这是有道理的,因为quote仍然只是吐出你给它到底是什么。 这就是为什么“文字”相同的数字和字符串有时被称为“自我引用” Lisp的说法。

还有一两件事:如果你发生了什么quote含有表达quote ? 也就是说,如果你的“双quote ”?

> (quote (quote 3))
'3

那里发生了什么? 那么,请记住, '实际上只是一个直接的缩写quote ,所以没有什么特别的事情发生了! 事实上,如果你的计划有一个方法来禁用打印时的缩写,它看起来就像这样:

> (quote (quote 3))
(quote 3)

不要被愚弄quote是特殊的:就像(quote (+ 1))这里的结果仅仅是一个普通的老名单。 事实上,我们可以得到的第一个元素淘汰之列:你猜它是什么?

> (car (quote (quote 3)))
quote

如果你猜3 ,你错了。 请记住, quote禁止所有的评价 ,并包含一个表达式quote符号仍然只是一个简单的列表。 玩这个在REPL,直到你舒服。

> (quote (quote (quote 3)))
''3
(quote (1 2 (quote 3)))
(1 2 '3)

报价是难以置信的简单,但它可以摘下来的,因为它是如何往往无视我们的传统评价模式的理解非常复杂。 没有特殊情况下,没有任何规则:事实上, 因为它是多么简单,它是混乱的。 它只是返回正是你给它什么,准确地陈述(因此命名为“报价”)。


附录A:Quasiquotation

所以,如果报价完全禁用的评价,有什么好处? 那么,除了使串,符号或数字均事先已知的,没有太多的名单。 幸运的是,quasiquotation的概念提供了一种方式打出来的报价,并返回到普通的评价。

基础知识是超级简单:而不是使用quote ,使用quasiquote 。 通常情况下,这个工程酷似quote在各个方面:

> (quasiquote 3)
3
> (quasiquote x)
x
> (quasiquote ((a b) (c d)))
((a b) (c d))

是什么让quasiquote特别是识别特殊符号, unquote 。 无论unquote出现在列表中,那么它是取代其中包含的任意表达式:

> (quasiquote (1 2 (+ 1 2)))
(1 2 (+ 1 2))
> (quasiquote (1 2 (unquote (+ 1 2))))
(1 2 3)

这允许您使用quasiquote构建一个有“洞”与填写各种各样的模板unquote 。 这意味着它可能实际上包括引用列表的内部变量的值:

> (define x 42)
> (quasiquote (x is: (unquote x)))
(x is: 42)

当然,使用quasiquoteunquote相当冗长,所以他们有自己的缩写,就像' 。 具体而言, quasiquote` (反引号)和unquote, (逗号)。 有了这些缩写,上面的例子是更适口。

> `(x is: ,x)
(x is: 42)

最后一点:quasiquote居然在球拍使用,而多毛的宏来实现,它是。 它扩大到的用途listcons ,当然, quote


附录B:实施listquote方案

实施list是因为如何“其余的参数”的语法著作超级简单。 这是你所需要的:

(define (list . args)
  args)

而已!

相比之下, quote是困难得多,事实上,这是不可能的! 这似乎是完全可行的,因为禁用评价的想法听起来很像宏。 然而,一个天真的尝试揭示了麻烦:

(define fake-quote
  (syntax-rules ()
    ((_ arg) arg)))

我们只是采取arg和吐回来了...但是这是行不通的。 为什么不? 好了,我们的宏观调控的结果进行评估,所以一切都是徒劳的。 我们也许能够扩展到东西有点像quote扩大至(list ...)和递归引用的元素,就像这样:

(define impostor-quote
  (syntax-rules ()
    ((_ (a . b)) (cons (impostor-quote a) (impostor-quote b)))
    ((_ (e ...)) (list (impostor-quote e) ...))
    ((_ x)       x)))

但不幸的是,没有程序宏,我们不能没有处理符号的quote 。 我们可以更贴近使用syntax-case ,但即使是这样,我们就只能是模拟quote的行为,而不是复制它。


附录C:球拍印刷约定

当试图在这个答案在球拍的例子,你可能会发现,他们不打印正如人们所期望。 通常情况下,他们可以与领先的打印' ,如下面的例子:

> (list 1 2 3)
'(1 2 3)

这是因为球拍,在默认情况下,打印结果表达式时可能。 也就是说,你应该能够将结果输入到REPL并获得相同的值返回。 我个人觉得这种行为很好,但试图了解行情时,它可能会造成混淆,所以如果你想将其关闭,呼叫(print-as-expression #f)或更改打印风格在DrRacket“写入”语言菜单。



文章来源: What is the difference between quote and list?