16

我最近买了Programming Scala,并且一直在阅读它。语言绝对不是我所期望的!具体来说,它似乎实现了我所知道的几乎所有编程语言的想法,在 Lisp 宏和 Haskell 的类型级副作用隔离之外。

坦率地说,这让我有些不知所措。虽然我认为有这么多工具可供我使用是件好事,但我真的只是在 JVM 上寻找一种强类型的函数式语言。我想我可能会以这种方式使用 Scala,但我想如果我与任何库交互或浏览其他任何人的代码,我会遇到很多这种高级(对我而言)OOP 东西——特征和“对象层次结构”线性化”,所有这些抽象和压倒一切的业务、单例、包和伴随对象、隐式转换……更不用说各种语法快捷方式和糖了。

人们常常哀叹程序员试图将一种语言的风格硬塞到另一种语言中,这有很多很好的理由。但并非所有语言都像 Scala 那样具有多范式,所以也许它的社区有不同的看法?例如,在 F# 中,似乎在编程风格和使用多少 OOP 方面存在一些余地。但是仅仅从阅读中我不确定这对 Scala 是否也是一个好的哲学。

更有经验的 Scala 程序员可以在这里帮助我吗?为清楚起见进行编辑:基本上,我可以安全地仅(或大部分)使用 Scala 的 FP 功能,而不必担心其高级 OOP 方面吗?

对不起,漫无边际的问题!

4

4 回答 4

16

您看到的一件事是 Scala 是JVM 上的一种强类型函数式语言

Scala不仅仅是一种函数式语言。它一开始确实是一个(Funnel: http: //lamp.epfl.ch/funnel/),但后来扩展使其成为一种面向对象的语言,其明确目标是使其与 Java 类具有很强的互操作性。

抽象、覆盖和包都是这种互操作性的例子。


其余的可能不被视为新功能,而只是从 Java 中删除限制。一次拿一个:

特征和对象层次线性化

移除 Java 接口只能包含抽象方法的限制。线性化是 Scala 解决钻石继承问题的方式,否则这会导致。

单身人士

Java 静态方法是其 C++ 语法遗产的遗留物,这反过来又添加了它们以更好地支持与 C 互操作的过程风格需求。静态方法非常不面向对象(请参阅这个问题:Why are singleton objects more object-oriented ? )

伴生对象

允许使用单例代替静态方法,并使用它们的特权访问权限。

隐式转换

Java 已经做到了这一点,但它仅限于将对象和原语隐式转换为字符串,如在表达式中"" + 3。Scala 只是扩展了这个想法,并允许程序员将其用于其他转换。

于 2010-11-22T16:59:30.497 回答
8

让我对凯文的回答添加一些评论。

特征主要用作抽象(松散地说,与 Haskell 类型类定义抽象的方式相同)和混合。因此,我的代码可能使用 Map 特征,但它实际上使用的是 HashMap 等类型的实例。相反,如果我希望我的“服务”类型具有日志记录功能,我可能会混合使用可重用的日志记录特征。

幸运的是,除了简单的情况之外,您很少需要考虑线性化算法,例如,我可以混合一个拦截(包装)方法调用的特征,以记录该方法被调用的事实。该算法需要处理更复杂的线性化情况(就像我们在书中展示的示例),但实际上如此复杂的类型是一个糟糕的设计,恕我直言。

单例,包括特殊的子集伴随对象,旨在使一切都成为对象,但您也可以将它们视为包装函数的命名空间,可能还有一些状态。

隐式转换非常有用,如果有点“神奇”的话。您可能会发现了解它们如何用于模拟 Haskell 类型类很有用。这是 Debasish Ghosh 的一篇很棒的文章:http: //debasishg.blogspot.com/2010/06/scala-implicits-type-classes-here-i.html

于 2010-11-22T18:00:38.837 回答
7

我认为这个问题肯定有一个坚实的观点。通过研究任何库如何处理异常来阐明这一点。

如果您与 Java 库交互,任何方法都可能引发异常。这可以是明确的,通过检查的异常 - 或透明的(从 API 角度来看),通过运行时异常。Either作为一个可能试图使用更多功能类型来指示失败(或scalaz的)的程序员,你应该怎么做Validation

我完全不清楚这将如何在 scala 中发挥作用(即解决问题并选择纯功能方法)。当然,它可能会产生许多不同风格的编码。也就是说,在 scala 的功能方面有很多丰富和有用的东西可供您选择;当然,您的程序中的这种功能性代码和命令式代码的混合当然是可以一起工作的。尽管功能纯粹主义者当然可能不同意这是否是最佳情况。

对于它的价值,我发现在我的程序中应用函数范式已经无休止地改进了我的代码。由于我没有尝试过HaskellF#,我无法告诉您最终结果是更好还是更差。

但它用 Java 擦了擦地板;在我看来,在 JVM 上实现这一点(具有与我们所有 Java 库共存的实际优势)是一个杀手级应用程序。


在边缘,当您开始更多地使用 scala 的功能方面时,您将遇到许多问题。这些是最明显的:

  • 缺乏隐式函数柯里化(即 和 的等价A => B => C(A, B) => C
  • 缺少隐式函数元组(即 n 元函数和以 n 元组为参数的 1 元函数之间的等价性)
  • 对部分应用的类型构造函数缺乏推理(M[A]例如,与 with等价Either[Int, A]

这两个问题都使得应该是漂亮和清晰的功能代码,丑陋和晦涩。

于 2010-11-23T00:04:27.020 回答
3

虽然我已经开始在 scala 中编程,但我绝对不是 scala 社区中更有经验的成员。但我长期使用另一种语言——python,它在较小程度上也有类似的情况。它支持过程式、面向对象和函数式风格。我发现虽然有些人倾向于坚持一个极端,但许多人结合了不同风格的结构。因此,惯用的 python 将包括大量使用列表推导、一等、高阶和部分函数,​​即使这些函数处理的数据是对象。然而,值得注意的是,多年来,趋势已经略微转向功能性。

我认为鉴于 scala 支持的样式的包容性,很可能没有一种正确的方法来解决问题。但是我不会感到惊讶的是,大部分程序员慢慢倾向于一种明智地使用两者的风格,即使他们仍然容忍希望坚持一个极端的程序员。

于 2010-11-22T17:57:26.753 回答