坚持Scala中的功能范式的功效

J C*_*per 16 paradigms programming-languages functional-programming scala jvm-languages

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

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

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

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

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

Kev*_*ght 16

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

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

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


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

特征和对象层次线性化

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

单身

Java静态方法是它的C++语法遗产的宿醉,它反过来又添加它们以更好地支持与C语言互操作的程序样式需求.静态方法非常不面向对象(请参阅此问题:为什么单例对象更加面向对象?)

伴侣物

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

隐式转换

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


Dea*_*ler 8

让我为凯文的回答添加一些评论.

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

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

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

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


oxb*_*kes 7

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

如果您与Java库交互,任何方法都可能抛出异常.这可以是显式的,通过检查的异常 - 或透明地(从API的角度来看),通过运行时异常.什么是你应该做这个,作为一个程序员谁可能会尝试使用更多的功能Either类型来表示失败(或scalazValidation)?

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

对于它的价值,我发现功能范例在我的程序中的应用已经改进了我的代码.由于我没有尝试过HaskellF#,我无法告诉你最终结果是好还是坏.

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


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

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

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

  • 同意,这个问题有很多优点.鉴于目前声称"Java很简单且Scala很复杂,因为它不是Java"的人数,我发现看到其他视角令人耳目一新.特别是"Scala很复杂,因为它从Java继承了这个复杂的面向对象的遗产" (3认同)