【问题标题】:Motivation for Scala underscore in terms of formal language theory and good style?Scala 的动机强调形式语言理论和良好风格?
【发布时间】:2014-09-10 10:45:14
【问题描述】:

为什么很多人说在 Scala 中使用下划线是好习惯,并且让你的代码更可读?他们说动机来自于形式语言理论。尽管如此,许多程序员,尤其是来自其他语言的程序员,尤其是那些具有匿名函数的程序员,更喜欢不使用下划线,特别是对于占位符。

那么下划线的意义何在?为什么 Scala(以及 om-nom-nom 指出的其他一些函数式语言)有下划线?就复杂性和语言理论而言,正式的基础是什么,为什么它经常良好的风格使用它?

【问题讨论】:

  • 我不会说 Scala 率先将 _ 用作占位符值——它早在 Scala 之前就已经在 OCaml 或 ML 等语言中出现了(后者已经出现了 40 年) ,不确定_ 单独)。 Scala 只是继承了他们的传统,并在不同的领域接受了它

标签: scala functional-programming programming-languages


【解决方案1】:

语言学

Scala 中大多数下划线使用的起源和动机是允许人们构造表达式和声明,而无需总是给出语言的每个变量(我的意思是谓词演算中的“变量”,而不是编程中的)一个名字。我们在自然语言中一直使用这个,例如,我在这句话中使用“this”来指代前一句中的一个概念,并且使用“this”来指代这句话,而不会混淆我的意思。在自然语言中,这些词通常被称为“pronouns”、“anaphors”、“cataphors”,指称“antecedent strong>”或“postcedent”,理解/取消引用它们的过程称为“anaphora”。

算法信息论

如果我们必须先命名自然语言中的每一个“事物”,然后才能引用它,类似地,为了量化每一种事物类型,就像在谓词演算和大多数编程语言中一样,那么说话就会变得非常冗长缠绕。多亏了上下文,我们可以推断出“this”、“it”、“that”等词的含义,我们很容易做到。

为什么要将这种简单、优雅、高效的交流方式限制在自然语言上呢?所以它被添加到 Scala 中。

如果我们确实试图命名每一个“事物”或“事物的类型”,句子会变得如此冗长和复杂,以至于由于冗长和引入冗余符号而变得非常难以理解>。添加到句子中的符号越多,理解起来就越困难,因此这就是为什么它是一种很好的做法,不仅在自然语言中,在 Scala 中也是如此。事实上,人们可以用 Kolmogorov 复杂性来形式化这个断言,并证明采用占位符的句子序列比不必要地命名所有内容的句子复杂度更低(除非在每个实例中名称完全相同,但这通常没有意义)。因此,我们可以肯定地说,与某些程序员的看法相反,占位符语法更简单、更易于阅读

它在使用中存在一些阻力的原因是,如果一个人已经是一名程序员,则必须努力重新训练大脑,不要命名所有东西,就像(如果他们能记得的话)他们可能已经找到了学习首先编写代码需要相当大的努力。

示例

现在让我们更正式地看一些具体的用途:

占位符语法

表示“它”、“他们”、“那个”、“他们的”等(即代词),例如1

lines.map(_.length)

可以读作“将行映射到它们的长度”,类似地我们可以将lineOption.map(_.length)读作“将行映射到它的长度”。就复杂性理论而言,这比“对于行中的每个 'line',取 'line' 的长度”更简单 - 这将是 lines.map(line => line.length)

与类型注释一起使用时,也可以读作“the”(定冠词),例如

(_: Int) + 1

" 整数加 1"

存在类型

表示“某种类型”(“某些”是代词),例如

foo: Option[_]

表示“foo 是一个选项某种类型的”。

高级类型参数

再一次,基本上意味着“某种类型”(“某些”是代词),例如

class A[K[_],T](a: K[T])

可以读作“A类需要一些K某种类型的 ...”

模式匹配通配符

表示“任何东西”或“随便什么”(代词),例如

case Foo(_) => "hello"

可以读作“对于包含任何内容的 Foo,返回 'hello'”,或“对于包含任何内容的 Foo,返回 'hello'”

导入通配符

表示“一切”(代词),例如

import foo._

可以读作“从 foo 导入所有内容”。

默认值

现在我把它读成“a”(不定冠词),例如

val wine: RedWine = _

“给我一杯红酒”,服务员应该给你全屋红。

下划线的其他用途

下划线的其他用法与本问答的重点无关,但我们简要讨论一下

忽略的值/参数/提取

允许我们以明确的“模式安全”方式忽略事物。例如

val (x, _) = getMyPoint

说,我们不打算使用第二个坐标,所以当你在代码中找不到用途时,不必大惊小怪。

导入隐藏

只是说“除了”(介词)的一种方式。

功能应用

例如

val f: String => Unit = println _

这是一个有趣的词,因为它在语言学中有一个确切的类比,即名词化,“使用动词、形容词或副词作为名词短语的头部,带有或没有形态转换” - 维基百科。更简单地说,就是将动词形容词变成名词的过程。

在特殊方法名中使用

纯粹是语法问题,与语言学无关。

【讨论】:

  • 我喜欢与自然语言进行比较。
  • 关于 Scala 中下划线的所有用法存在一个规范问题。想出一种尽可能多的自然语言并将这两个问题联系起来会很有趣:stackoverflow.com/questions/8000903/…
  • @JörgWMittag 是的,我已经尽可能多地尝试了,我会添加更多,我已经将这个答案链接到 Owens。我正在努力为“忽略的变量”找到一个很好的 NL 类比,因为我很难真正想到 Scala 本身中的一个 stackoverflow.com/questions/25778616/…
猜你喜欢
  • 2016-10-04
  • 1970-01-01
  • 1970-01-01
  • 2019-01-13
  • 2019-08-10
  • 2017-11-30
  • 1970-01-01
  • 1970-01-01
  • 2016-07-17
相关资源
最近更新 更多