Scala 与 F# 的问题:它们如何统一 OO 和 FP 范式?

2023-12-19

Scala 和 F# 统一 OO 和 FP 范式的方法之间的主要区别是什么?

EDIT

每种方法的相对优点和缺点是什么?尽管支持子类型化,如果 F# 可以推断函数参数的类型,那么为什么 Scala 不能呢?


我看过 F#,做过低级教程,所以我对它的了解非常有限。然而,对我来说很明显,它的风格本质上是函数式的,OO 更像是一个附加组件——更像是一个 ADT + 模块系统,而不是真正的 OO。我得到的感觉可以最好地描述为好像其中的所有方法都是静态的(如 Java 静态)。

例如,请参阅使用管道运算符的任何代码 (|>)。从以下内容中获取此片段F# 上的维基百科条目 http://en.wikipedia.org/wiki/F_Sharp_(programming_language):

[1 .. 10]
|> List.map     fib

(* equivalent without the pipe operator *)
List.map fib [1 .. 10]

功能map不是列表实例的方法。相反,它的工作方式就像一个静态方法List模块将列表实例作为其参数之一。

另一方面,Scala 是完全面向对象的。首先,我们从该代码的 Scala 等效版本开始:

List(1 to 10) map fib

// Without operator notation or implicits:
List.apply(Predef.intWrapper(1).to(10)).map(fib)

Here, map是实例上的方法List。类似静态的方法,例如intWrapper on Predef or apply on List,则更为罕见。然后还有一些函数,比如fib多于。这里,fib不是一个方法int,但它都不是静态方法。相反,它是一个object——我认为 F# 和 Scala 之间的第二个主要区别。

让我们考虑一下 Wikipedia 中的 F# 实现以及等效的 Scala 实现:

// F#, from the wiki
let rec fib n =
    match n with
    | 0 | 1 -> n
    | _ -> fib (n - 1) + fib (n - 2)

// Scala equivalent
def fib(n: Int): Int = n match {
  case 0 | 1 => n
  case _ => fib(n - 1) + fib(n - 2)
}

上面的 Scala 实现是一个方法,但是 Scala 将其转换为一个函数,以便能够将其传递给map。下面我将对其进行修改,使其成为返回函数的方法,以展示函数在 Scala 中的工作原理。

// F#, returning a lambda, as suggested in the comments
let rec fib = function 
    | 0 | 1 as n -> n 
    | n -> fib (n - 1) + fib (n - 2)

// Scala method returning a function
def fib: Int => Int = {
  case n @ (0 | 1) => n
  case n => fib(n - 1) + fib(n - 2)
}

// Same thing without syntactic sugar:
def fib = new Function1[Int, Int] {
  def apply(param0: Int): Int = param0 match {
    case n @ (0 | 1) => n
    case n => fib.apply(n - 1) + fib.apply(n - 2)
  }
}

因此,在 Scala 中,所有函数都是实现该特征的对象FunctionX,它定义了一个名为apply。如此处和上面的列表创建所示,.apply可以省略,这使得函数调用看起来就像方法调用一样。

最后,Scala 中的所有内容都是一个对象——以及类的实例——并且每个这样的对象都属于一个类,并且所有代码都属于一个方法,该方法以某种方式执行。甚至match在上面的例子中以前是一个方法,但很早之前已经被转换为关键字以避免一些问题。

那么,它的功能部分又如何呢? F# 属于最传统的函数式语言家族之一。虽然它没有一些人们认为对函数式语言很重要的功能,但事实是 F# 的功能是default, 可以这么说。

另一方面,Scala 的创建目的是unifying函数式模型和面向对象模型,而不是仅仅将它们作为语言的单独部分提供。它的成功程度取决于您认为什么是函数式编程。以下是 Martin Odersky 关注的一些事情:

  • 函数就是值。它们也是对象——因为在 Scala 中所有值都是对象——但是函数是可以操作的值这一概念是一个重要的概念,其根源可以追溯到最初的 Lisp 实现。

  • 对不可变数据类型的强大支持。函数式编程始终关注减少程序的副作用,函数可以作为真正的数学函数进行分析。因此,Scala 很容易使事物变得不可变,但它没有做 FP 纯粹主义者批评的两件事:

    • 它没有产生可变性harder.
    • 它不提供效果系统,通过它可以静态跟踪可变性。
  • 支持代数数据类型。代数数据类型(称为 ADT,它也代表抽象数据类型,这是一种不同的东西)在函数式编程中非常常见,并且在 OO 语言中通常使用访问者模式的情况下最有用。

    与其他所有事物一样,Scala 中的 ADT 是作为类和方法实现的,并带有一些语法糖,使它们可以轻松使用。然而,Scala 在支持它们方面比 F#(或其他函数式语言)要详细得多。例如,代替 F#|对于 case 语句,它使用case.

  • 支持非严格性。非严格性意味着仅按需计算内容。它是 Haskell 的一个重要方面,它与副作用系统紧密集成。然而,在 Scala 中,非严格性支持相当胆怯且处于初级阶段。它可用并使用,但方式受到限制。

    例如,Scala 的非严格列表,Stream,不支持真正的非严格foldRight,就像哈斯克尔所做的那样。此外,只有当非严格性是语言中的默认值而不是选项时,才能获得非严格性的一些好处。

  • 支持列表理解。实际上,Scala 称之为用于理解,因为它的实现方式完全脱离了列表。用最简单的术语来说,列表推导式可以被认为是map示例中显示的函数/方法,尽管嵌套了映射语句(支持 withflatMap在 Scala 中)以及过滤(filter or withFilter在 Scala 中,取决于严格要求)通常是预期的。

    这是函数式语言中非常常见的操作,并且语法通常很简单——就像在 Python 中一样in操作员。同样,Scala 比平常更加冗长。

在我看来,Scala 在结合 FP 和 OO 方面是无与伦比的。它从频谱的 OO 一侧朝向 FP 一侧,这是不寻常的。大多数情况下,我看到 FP 语言都在处理 OO 问题——而且它feels向我解决了这个问题。我想 Scala 上的 FP 对于函数式语言程序员来说可能有同样的感觉。

EDIT

Reading some other answers I realized there was another important topic: type inference. Lisp was a dynamically typed language, and that pretty much set the expectations for functional languages. The modern statically typed functional languages all have strong type inference systems, most often the Hindley-Milner http://en.wikipedia.org/wiki/Hindley-Milner#algorithm1 algorithm, which makes type declarations essentially optional.

Scala can't use the Hindley-Milner algorithm because of Scala's support for inheritance2. So Scala has to adopt a much less powerful type inference algorithm -- in fact, type inference in Scala is intentionally undefined in the specification, and subject of on-going improvements (it's improvement is one of the biggest features of the upcoming 2.8 version of Scala, for instance).

然而,最终,Scala 要求所有参数在定义方法时声明其类型。在某些情况下,例如递归,还必须声明方法的返回类型。

Scala 中的函数通常有其类型inferred不过,而不是声明。例如,这里不需要类型声明:List(1, 2, 3) reduceLeft (_ + _), where _ + _实际上是一个类型的匿名函数Function2[Int, Int, Int].

同样,变量的类型声明通常是不必要的,但继承可能需要它。例如,Some(2) and None有一个共同的超类Option,但实际上属于不同的子类。所以人们通常会声明var o: Option[Int] = None以确保分配了正确的类型。

这种有限形式的类型推断比静态类型的 OO 语言通常提供的要好得多,这给了 Scala 一种轻盈的感觉,但也比静态类型的 FP 语言通常提供的要差得多,这给了 Scala 一种沉重的感觉。 :-)

Notes:

  1. 实际上,该算法起源于Damas和Milner,他们将其称为“算法W”,根据维基百科 http://en.wikipedia.org/wiki/Type_inference#Hindley.E2.80.93Milner_type_inference_algorithm.

  2. 马丁·奥德斯基在评论中提到here http://www.codecommit.com/blog/scala/universal-type-inference-is-a-bad-thing that:

    Scala 没有 Hindley/Milner 类型推断的原因是 很难与诸如 重载(临时变体,而不是类型类),记录 选择和子类型化

    他接着表示,这实际上可能并非不可能,这归结为一个权衡。请访问该链接以获取更多信息,并且,如果您确实提出了更清晰的声明,或者更好的是,以某种方式提出了一些论文,我将不胜感激。

    让我感谢乔恩·哈洛普 https://stackoverflow.com/users/13924/jon-harrop查找这个,正如我所假设的那样不可能的。好吧,也许是这样,但我找不到合适的链接。但请注意,这不是继承alone导致问题。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Scala 与 F# 的问题:它们如何统一 OO 和 FP 范式? 的相关文章

随机推荐

  • Rails:相同两个模型之间的多个联接表

    我有两个模型 玩家和事件 它们之间有两个连接表 参与者和课程 class Event has many participants has many players through participants has many lessons
  • SSIS 包中 ReadUncommissed 隔离级别的解决方法

    SSIS 中的 ReadUncomfilled IsolationLevel 是 Microsoft 承认的一个错误 但 不会修复 如下所述 http connect microsoft com SQLServer feedback det
  • 使用extend.js有什么好处?

    我刚刚认识扩展 js https github com searls extend js 并且想知道使用该库是否比使用本机 JavaScript 具有附加价值 让我演示一下 With 扩展 js 我会声明一个命名空间 如下所示 extend
  • MySQL:永久设置 sql_mode

    通过 MySQL 命令行客户端 我尝试设置全局 mysql mode SET GLOBAL sql mode TRADITIONAL 这适用于当前会话 但在我重新启动服务器后 sql mode 将返回到其默认值 一个空字符串 如何将 sql
  • Codeigniter - 使用force_download函数下载文件

    我正在使用最新的 CI 我在当地工作时没有任何问题 但是当我将作品转移到实时服务器时 我遇到了问题 当我从下载选项卡下载文件时 文件将以正确的大小和格式下载 但是当我打开下载的文件时 例如 如果是图像 则图像不显示 或者如果是单词 则要求选
  • Java 不运行带参数的准备语句

    我正在使用PreparedStatement 来查询我的表 不幸的是 我没能做到这一点 我的代码很简单 PreparedStatement preparedStatement connection prepareStatement Sele
  • 我们可以在 Cubism 上使用自定义 JSON 数据吗?

    我看到了立体图 它们简直太神奇了 我有一个很大的 JSON 文件 其中包含 1000 个条目 其中包含时间戳和值 整数 Cubism 可以绘制这些图吗 我似乎找不到这方面的文档 Cubism 通常适用于实时数据 但您可以实现一个仅从 JSO
  • Swift:获取字典中键的数量

    对于快速数组 我们可以简单地使用count属性来找出集合中有多少个元素 然而 我们不能对字典键做同样的事情 执行此操作的唯一方法是使用 for 循环和计数器吗 var myDict String AnyObject intialize di
  • FFmpeg:如何将带有黑边的垂直视频转换为背景边模糊的 16:9 视频

    如何使用 FFmpeg 实现这一点 没有 FFmpeg 的示例 Adobe After Effects http www youtube com watch v yCOrqUA0ws4 索尼维加斯专业版 http www youtube c
  • Snakemake 和 pandas 语法

    我有一个输入文件如下 SampleName Run Read1 Read2 A run1 test true data 4k R1 fq test true data 4k R2 fq A run2 test samples A fastq
  • SQL Server 2012经典asp连接字符串

    我安装了 SQL Server 2012 Express 其中有一个名为BRD我创造的 我还创建了一个测试表 tempDemo 和一个测试存储过程 getStList 在里面BRD数据库 当我在查询窗口中运行存储过程时 它会起作用 因此我相
  • 移动设备上的视觉视口与布局视口

    我刚刚读了一篇关于视口的好文章 http www quirksmode org mobile viewports2 html这给我留下了一些关于移动设备上的视觉视口与布局视口的问题 布局视口的宽度和高度等于任何值 可以以最大缩小模式显示在屏
  • 在 Android 中制作自定义可绘制形状

    我想要像下面这样绘制 我可以在两个不同的 xml 文件中制作矩形和三角形 但我想联合它们来制作这样的可绘制对象 Use layer list制作这个自定义形状drawable res drawable custom shape xml
  • UnsatisfiedLinkError:无法从加载程序加载 X

    我正在尝试使用本机代码创建一个 android 项目来调用 OpenGL 函数 我正在按照本指南来启动该项目 http www learnopengles com calling opengl from android using the
  • 如何让 HtmlUnit 在 Android 下工作?

    这是我的代码 import com gargoylesoftware htmlunit WebClient import com gargoylesoftware htmlunit html HtmlPage final WebClient
  • 关于并行架构的设计模式有什么好的资源吗?

    一些背景知识 我正在开始使用 GPGPU OpenCL 我正在使用 java 包装器 jogamp jocl http jogamp org jocl www 希望它能为我提供一种抽象低级细节并在更高级别使用标准 OOP 的方法 我已经从各
  • delphi 使用记录作为 TDictionary 中的键

    可以使用记录作为 TDictionary 中的键值吗 我想根据字符串 整数和整数的组合来查找对象 TUserParKey record App string ID integer Nr integer end var tmpKey TUse
  • 多个 fbAsyncInit?

    在我的网站中 我使用 Facebook JS SDK 的异步加载 为了实际设置它 我在 window fbAsyncInit 函数中使用标准 FB init 然而问题是 在我的网站中 这个功能位于每个页面上 然而 当我在子页面中时 由于网站
  • 如何替换 Android Gradle 构建文件中已弃用的 PackagingOptions

    我已经迁移到 gradle 8 我的 android 构建 gradle 文件显示 plugins id com android application version 8 1 0 alpha01 apply false id com an
  • Scala 与 F# 的问题:它们如何统一 OO 和 FP 范式?

    Scala 和 F 统一 OO 和 FP 范式的方法之间的主要区别是什么 EDIT 每种方法的相对优点和缺点是什么 尽管支持子类型化 如果 F 可以推断函数参数的类型 那么为什么 Scala 不能呢 我看过 F 做过低级教程 所以我对它的了