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: '+