在Scheme中,标识符和符号有何区别?

5
我正在尝试理解Scheme元循环求值器如何处理引用表达式与符号数据的不同之处。
Stack Overflow问题“Lisp/Scheme中的符号到底是什么?”的被接受答案定义了Scheme中的“符号”数据对象:
在Scheme和Racket中,符号类似于不可变的字符串,恰好被内部化。
被接受的答案写道,在Scheme中,标识符和符号之间存在内置的对应关系:
要调用一个方法,您需要查找与该方法名称对应的符号。Lisp/Scheme/Racket使这变得非常容易,因为语言已经在标识符(语言语法的一部分)和符号(语言中的值)之间建立了内置的对应关系。
为了理解这种对应关系,我阅读了《Scheme及其实现简介》中的{{link2:“关于标识符的说明”}}页面。
Scheme标识符(变量名、特殊形式名和关键字)几乎具有与Scheme符号对象字符序列相同的限制,这不是巧合。大多数Scheme实现恰好是用Scheme编写的,并且符号对象在解释器或编译器中用于表示变量名。
基于上述内容,我想知道我对以下会话中发生的事情的理解是否正确:
user@host:/home/user $ scheme
MIT/GNU Scheme running under GNU/Linux
Type `^C' (control-C) followed by `H' to obtain information about interrupts.

Copyright (C) 2011 Massachusetts Institute of Technology
This is free software; see the source for copying conditions. There is NO warranty; not even for
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

Image saved on Sunday February 7, 2016 at 10:35:34 AM
  Release 9.1.1 || Microcode 15.3 || Runtime 15.7 || SF 4.41 || LIAR/x86-64 4.118 || Edwin 3.116

1 ]=> (define a (lambda (i) (+ i 1)))

;Value: a

1 ]=> a

;Value 13: #[compound-procedure 13 a]

1 ]=> (quote a)

;Value: a

1 ]=> (eval a (the-environment))

;Value 13: #[compound-procedure 13 a]

1 ]=> (eval (quote a) (the-environment))

;Value 13: #[compound-procedure 13 a]

1 ]=>

  1. 第一个define语句是由求值器捕获的特殊形式,它在全局环境中创建了一个将符号a绑定到复合过程对象的绑定。

  2. 在顶层写下a会使求值器收到符号对象'a,这将计算为在全局环境中指向'a的复合过程对象。

  3. 在顶层写下(quote a)会使求值器收到符号列表('quote 'a));这个表达式是求值器捕获的特殊形式,它将计算为引用的表达式,即符号对象'a

  4. 写下(eval a (the-environment))会使求值器收到符号列表('eval 'a ...)(忽略环境)。求值器执行查找'eval,得到eval编译过程对象,查找'a,得到复合过程。最后,顶层求值器将eval过程应用于其参数,由于复合过程是自求值的(在Scheme48中不是),因此表达式的最终值是复合过程本身。

  5. 写下(eval (quote a) (the-environment))会使求值器收到符号列表('eval ('quote 'a) ...)。求值器执行查找'eval,得到eval编译过程对象。它计算表达式('quote 'a),这将产生符号对象'a。最后,顶层求值器将eval过程应用于'a,它是一个符号对象,因此调用环境查找,得到复合过程。

这个解释是否正确描述了Scheme解释器如何区分语言中的符号对象和标识符?这些描述中是否存在基本误解?

这个解释在高层次上描述了Scheme解释器如何区分语言中的符号对象和标识符吗?它无法做到这一点,因为它的1到5点甚至没有提到“标识符”这个词。 - Kaz
@Kaz 好的,我认为“标识符”是在提示符号之前写入的令牌。也许我应该问:“Scheme解释器如何处理顶层标识符,并在内部使用符号?” - jII
1
@jesterll 用Scheme编写的Scheme解释器不会看到词法标识符;它必须依靠某个read函数来扫描文本并生成数据结构,然后纯粹地解释该数据结构。 只有在从头开始编写Scheme实现时才需要自己处理这些问题;但即使那样,你也要以同样的方式将读取与解释分开处理。 - Kaz
标识符是指在我们的程序中引用绑定的名称。符号就像指向自身的命名指针。 - Will Ness
2个回答

5
在4.2词法语法中,R6RS Scheme报告使用术语"标识符"来指代字符级语法。也就是说,大致上,“标识符”意味着当表达式成为对象时,从中构造符号的词法令牌。然而,在文本的其他地方,“标识符”似乎被自由地用作“符号”的同义词。例如,“Scheme允许标识符表示包含值的位置。这些标识符称为变量。”(1.3变量和绑定)。基本上,规范在这个术语上似乎很宽松。根据上下文,标识符或者是与符号(一个对象)相同的东西,或者是:来自词法语法的语法类别。
在一句话中,如果说某个字符可能出现在标识符中,那么上下文显然是词法语法,因为符号对象是原子而不是字符串;它不包含任何内容。但是当我们谈论标识符表示内存位置(即变量)时,这就是符号;我们已经超越了什么样的令牌可以在文本源代码中产生符号的问题。
问题中链接的教程《Scheme及其实现简介》使用了自己特殊的定义“标识符”,这与Scheme语言不一致。它暗示了标识符是“变量名、特殊形式名称和关键字”(因此不支持不是变量名的符号不是标识符的说法)。

我猜测这是为了区分标识符和符号而做出的尝试,例如当某个编译器解析程序时,没有为标识符构建符号 - 例如通过不使用READ来读取源作为s表达式。因此,您可以拥有/使用Scheme变体的语法,而与s表达式无关。 - Rainer Joswig

4

前言:提前为告诉您已经知道的内容道歉!

你的第一句话引发了我一个关于XY的问题。你写道:“我正试图理解Scheme元循环求值程序如何处理引用表达式与符号数据的不同之处。” 你所说的“Scheme元循环求值程序”是什么?此外,“符号数据”又是什么?这两个术语都让我觉得你想问更高级别的问题。

无论如何,你的标题暗示了一个关于标识符和符号之间区别的问题。区别在于:

“标识符”是一个语法类别。也就是说,假设我们把文本文件分成令牌。有些令牌会是左括号,有些会是右括号,有些会是数字,有些会是标识符。每种语言都有自己的语法类别,但许多语言将“标识符”称为“类似单词的东西,通常可以是函数名或变量名等”。

而“符号”则是Scheme和Lisp系统中一种特定类型的值。Scheme有许多不同类型的值:数字、布尔值、字符串、对、符号等等。

在Scheme中,当开发解析器/解释器/编译器/其他工具时,使用符号(值)来表示标识符(语法实体)非常方便。具体来说,“引用”有一种特殊的能力,可以将某些宿主语言令牌序列转换为符号、数字、字符串和布尔值列表。您不需要利用这个功能,但它可以减少很多代码。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接