本 EEP 提出了如何在 Erlang 中以向后兼容的方式扩展变量和原子名称以包含 Unicode 字符。
www.example.com
这样的 ASCII 域名(在 Erlang 中不需要引号)一样方便。字符集名称,XID_Start、XID_Continue、Lu、Lt、Lo、Pc、Other_Id_Start,取自 Unicode 和 UAX#31。
Lu = upper case letters
Lt = title case letters
Ll = lower case letters
Lo = non-case letters (Arabic, Chinese, and so on)
Pc = connector punctuators, including the low line (_) and
a number of other characters like undertie (‿).
Other_Id_Start = script capital p, estimated symbol,
katakana-hiragana voiced sound mark, and
katakana-hiragana semi-voiced sound mark.
variable ::= var_start var_continue*
var_start ::= (XID_Start ∩ (Lu ∪ Lt ∪ Other_Id_Start)) ∪ Pc
var_continue ::= XID_Continue ∪ "@" \ "ªº"
这里选择 XID 遵循 Python。它确保变量的规范化仍然是一个变量。实际上,Unicode 变量应该被规范化。Unicode 有足够多的相似字符,我们不能期望“看起来相同 <=> 是相同的”为真,但我们应该朝着这个方向走一段路。
不区分字母大小写的脚本中的变量必须以某个特殊字符开头,以确保它们不会被误认为是未加引号的原子。基本多语言平面中有 10 个 Pc 字符。Erlang 解析器特殊处理以下划线开头的变量:如果它是单例,则不会发出警告。一种方法是说,这种特殊处理不适用于其他 9 个 Pc 字符。使用这种方法,‿ 不会是通配符,_隠者 应该是单例,而 ‿隠者 不应该。
当然,有些人可能会使用包含阿拉伯字母但不包含下连线之类的字体。我们可以通过修改下划线规则来解决这个问题,我建议这样做
Variable does not begin with a Pc character =>
should not be a singleton.
Variable is just a Pc character and nothing else =>
is a wild card.
Variable begins with a Pc character followed by an
Lu or Lt or Pc character =>
may be a singleton.
Variable begins with a Pc character followed by
a legal character other than an Lu or Lt or Pc character =>
should not be a singleton.
因此,‿ 是一个通配符,隠者 是一个原子,_隠者 不应该是单例,但是 __隠者 可能是单例。这条规则是对现有规则的一致概括。
unquoted_atom ::= "."? atom_start atom_continue*
atom_start ::= XID_Start \ (Lu ∪ Lt ∪ "ªº")
atom_continue ::= XID_Continue ∪ "@" \ "ªº"
| "." atom_start
再次,XID 的选择遵循 Python,并确保未加引号的原子的规范化仍然是一个未加引号的原子。未加引号的原子应该被规范化。
Erlang 未加引号的原子的细节有些微妙;我已经通过实验检查了我的理解。允许初始点,但总是被丢弃。这很奇怪,但它现在就是这样。
关键字具有未加引号的原子形式。没有引入新的关键字。
任何 Python 标识符或关键字都是 Erlang 变量或未加引号的原子或关键字,除非它包含“ª”或“º”。
@ 符号可以自由地出现在变量和未加引号的原子中,除了第一个字符,就像现在一样。
尽管它们在 Ll 集中,因此在技术上是小写字母,但在本提案中,变量名称或未加引号的原子中不允许使用“ª”和“º”,因为它们现在在 Erlang 中不允许使用。
点号后面不能跟大写字母、数字或下划线,就像现在一样。
我不确定在点号之后是否应该允许修饰符字母。
我不确定如何处理 Other_ID_Start 字符。脚本大写 p 看起来像大写 p,甚至在其名称中也有“大写”。所有其他“* SCRIPT CAPITAL *”字符都是大写字母。当然应该允许它作为变量的开头。估计符号看起来像放大的小写 e;其他看起来像字母的符号被归类为字母。您会期望这成为一个原子的开头。至于片假名-平假名发音标记,我完全没有直觉。将整个组分配给原子似乎是最安全的。
所有现有的变量名和未加引号的原子仍然合法,并且没有引入仅使用 Latin-1 字符的新变量或原子形式。
虽然打算与广大受众共享的 Erlang 文件仍然应该用英语编写,但如果人们在某个语言流畅的团队中工作,并且需求也用该语言编写,那么他们应该能够保持接近需求的术语,以免引入翻译错误。
整个设计朝着“如果有人想在 Erlang 文件中使用自己的脚本,他们应该能够以一种与一般其他编程语言一致的方式舒适地做到这一点”的方向发展。
这确实意味着会存在一些 Erlang 源代码文件,因为不熟悉脚本,熟练的 Erlang 程序员也无法解读。在 Unicode 6 中有超过 110,000 个字符,无论我们做什么,这种情况都会发生。一旦 Unicode 字符串可用,那么带引号的 Unicode 原子还会远吗?一旦它们成为可能,拒绝未加引号的 Unicode 原子并不能挽救普遍的可读性。它所能做的就是要求人们大量使用单引号而惹恼他们。老 Algol 程序员只会清楚地记得单引号的暴风雨对可读性造成了多大的损害。如果你可以使用 γαμμα 作为原子,那么拒绝 Γαμμα 有任何意义吗?
此 EEP 的目标之一是,如果 Erlang 文本仅包含 Latin-1 字符,那么它在新规则下应该合法,当且仅当它在旧规则下合法,并且在任一上下文中都应该具有相同的含义。在过渡期间,有些人会为遵循新规则的系统编写 Erlang 代码,并将其提供给使用 Latin-1 或至少是旧规则系统的人。他们不应该意外地引入不兼容性。这就是为什么我们现在必须禁止“ª”和“º”的原因。以后我们可能会解除该禁令。
我们有三种方法必须自定义 UAX 31 定义。
为了向后兼容,我们必须继续支持变量中的“@”和未加引号的原子中的“@”和“.”。
我们必须继续禁止包含 Latin-1 男性和女性序数指示符的未加引号的原子。
我们必须区分变量和未加引号的原子。
我们可能有第四种方法来定制它。Unicode 的 Ken Whistler 建议,他“看不出有什么意义”允许 LOW LINE 和 FULLWIDTH LOW LINE 之外的 Pc 字符,除非有遗留原因必须支持其他字符。如果 s 是合法的 ASCII 标识符,那么 s 的全角版本也应该是合法的标识符,所以绝对应该允许 FULLWIDTH LOW LINE。我发现使用 UNDERTIE 很酷,但它实际上是编辑的标记。如果我们现在拒绝其他 Pc 字符,我们总是可以在以后找到需要时允许它们;如果我们现在允许它们,以后就很难拒绝它们了。在定义中清楚地进行此更改需要稍加考虑,因此这是为下一个修订版准备的。
Dmitry Belyaev 提出了本地化关键字的问题。这超出了此 EEP 的范围,此 EEP 关注的是哪些字符序列是变量,哪些是关键字或未加引号的原子。在我们可以考虑本地化关键字之前,必须首先正确处理这个问题。
在 Ulrich Neumerkel 的建议下,于 11 月 5 日修改了前导下划线规则,以避免 _Œuvre 不会被接受为单例的问题。现在它可以了。这很讽刺,因为像 _Āporo 这样的毛利变量会被错误分类。
即使 Unicode 进行了修订,合法的 Erlang 文本也应该保持合法,这是非常可取的。UAX#31 和 稳定性 几乎满足了我们的需求。似乎在技术上可能存在的一个问题是,没有相反大小写对应项的大写或小写字母可能会更改其通用类别(如果它完全不再是字母,则会被赋予 Other_ID_Start 属性),因此以此类带大小写的孤立字符开头的标识符可能会从变量切换为未加引号的原子,反之亦然。确实存在一些带大小写的孤立字符,例如拉丁字母小写大写 M,但是大写的大写 M 会是什么?
一种可能性是向 Unicode 联盟提出这个问题,并在他们回复之前保持未解决。这个问题已经提出,并且给出了试探性回复“您可能无法依赖任何给定的标准属性用于特殊目的。特别是如果该属性不是正式稳定的”。下一步很可能是寻求对 UAX#31 进行修订,因为 Erlang 并不是唯一需要区分大小写的。
另一种可能性是,只有当 Lu 字符有小写对应形式时,它才能开始一个变量;只有当 Ll 字符有大写对应形式时,它才能开始一个非引用原子。由于“ß”和“ÿ”在 Unicode 中有大写对应形式,因此 Latin-1 非引用原子不会受到此规则的影响。大量的 Lo 字符也不会受到影响。
本文档已置于公共领域。