坚持Scala中功能范式的功效

时间:2010-11-22 16:12:38

标签: scala programming-languages functional-programming paradigms jvm-languages

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

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

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

更有经验的Scala程序员可以帮助我吗? 为了清晰起见编辑:基本上,我是否可以安全地使用Scala的FP功能而不用担心其高级OOP端?

抱歉这个漫无边际的问题!

4 个答案:

答案 0 :(得分:16)

您所看到的一件事是,Scala首先是JVM上强类型的函数语言

Scala不是只是一种功能语言。它确实从一开始(漏斗:http://lamp.epfl.ch/funnel/),但后来扩展为使其成为面向对象的语言,其明确目标是使其与Java类强大地互操作。

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


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

特征和对象层次结构线性化

删除Java接口只能包含抽象方法的限制。线性化是Scala如何解决钻石继承问题的原因。

<强>单身

Java静态方法是它的C ++语法遗产的宿醉,它反过来又添加它们以更好地支持与C互操作的程序样式需求。静态方法非常不面向对象(请参阅此问题:Why are singleton objects more object-oriented?

随播广告

允许使用单例代替静态方法,具有其特权访问权限。

隐式转化

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

答案 1 :(得分:8)

让我在凯文的回答中加上一些评论。

Traits主要用作抽象(松散地说,与Haskell类型类定义抽象的方式相同)和mixins。所以,我的代码可能会使用Map trait,但它确实使用了像HashMap这样的类型的实例。相反,如果我希望我的“服务”类型具有日志记录功能,我可能会混合使用可重用的日志记录特征。

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

Singletons,包括特殊子集伴随对象,旨在使所有东西成为一个对象,但你也可以只将它们视为命名空间包装函数和可能的某些状态。

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

答案 2 :(得分:7)

我认为这个问题肯定有一个重点。通过研究任何库如何处理例外来阐明它。

如果您与Java库交互,任何方法都可能抛出异常。这可以通过 checked 异常显式地,或者通过运行时异常透明地(从API角度来看)。作为一个程序员可能会尝试使用功能更强大的Either类型来表示失败(或 scalaz Validation),你应该怎么做呢? / p>

对我来说,这一点在scala中是如何发挥的(即接近问题和选择纯粹的功能方法)并不是很清楚。当然,它很可能产生许多不同风格的编码。也就是说,scala的功能方面有很多丰富而有用的东西可以选择;当然,在您的程序中将功能和命令性代码混合在一起是可能的。虽然功能 purist 当然可能不同意这是否是最佳情况。

对于它的价值,我发现在我的程序中应用功能范例已经改进了我的代码。由于我没有尝试 Haskell F#,我无法告诉您净结果是好还是坏。

但它用Java擦拭了地板;并且从我的角度来看,在JVM上获得 (具有与我们所有Java库共存的实际优势)是一个杀手级的应用程序。


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

  • 缺乏隐含功能 currying (即A => B => C(A, B) => C的等效性
  • 缺少隐式函数 tupling (即n-ary函数和以n元组为参数的1-ary函数之间的等价性)
  • 缺乏对部分应用类型构造函数的推断(即M[A]Either[Int, A]的等价性)

这两个问题都使得功能代码变得非常清晰,丑陋和模糊。

答案 3 :(得分:3)

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

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