33

Scala 和 Frege 都是针对 JVM 的类型化函数式语言。

Frege 更接近 Haskell,Scala 有更独立的历史。

但是如果我们不看句法上的差异,那么两者在允许的编程技术、风格、概念上有什么不同呢?

4

3 回答 3

41

恕我直言,两者都是非常好的语言,但就范式而言,Scala 的 OO 比 Frege 好,但 Frege 的功能比 Scala 好。关于差异,它主要归结为 Haskell 与 Scala,因为 Frege 是(或几乎,参见 Haskell 和 Frege 之间的差异用于 JVM 的 Haskell。

  1. Frege 的类型推断是全局的,因此我们不必像在 Scala 中那样频繁地注释类型(局部推断)。

  2. 在 Frege 中,模块只是类型和函数的命名空间,而 Scala 有更好的模块系统。http://2013.flatmap.no/spiewak.html

  3. 在 Frege 中,默认情况下函数是柯里化的,因此不需要额外的构造来应用部分函数。部分类型构造函数应用程序也是如此。

  4. 在弗雷格,没有defvs val,一切都是函数。因此,函数比 Scala 更一流。

  5. Frege 没有子类型,但类型系统在本机调用中计算出子类型。例如,您可以将 an 传递ArrayList给需要 Java 的函数List

    由于没有子类型化,在 Frege 中我们目前无法扩展 Java 类或实现接口(将来可能会支持),因此我们需要一个 Java 类来扩展/实现,但方法实现将从 Frege 传递作为函数。

  6. 在 Scala 中,调用 Java 很容易,但在 Frege 中,Java 类/方法必须在使用前声明(只是类型和纯度注释)。例如,要使用 Java 的LinkedList,

    data LinkedList a = native java.util.LinkedList where
        native add :: Mutable s (LinkedList a) -> a -> ST s Bool
        native get :: Mutable s (LinkedList a) -> Int -> ST s (Maybe a) throws
           IndexOutOfBoundsException
        native new :: () -> STMutable s (LinkedList a)
    

    在这里,由于函数会改变对象,所以它们必须在STmonad 中。另请注意,此处 Frege 还处理nullget方法返回的内容,因为它使用Maybe类型进行了注释。进入您的 Frege 程序的唯一方法null是通过本机接口,因为 Frege 没有 null 的概念。

    另一个例子: pure native floor Math.floor :: Double -> Double

    这表明该函数是纯函数,因此签名直接反映了原始 Java 签名,没有IOor ST

  7. Frege 没有 Scala 中的变量,var并且副作用通过类型更加明确。(只是 no null, novar​​和显式的副作用让 Frege 更有趣,至少对我来说。从某种意义上说,Frege 就像 Haskell 一样,是 JVM 的“良好的命令式编程语言”!)

  8. 作为 Haskell 方言,Frege 对 Functors、Applicatives、Monads 和其他功能“模式”更自然,并且在它的标准库中包含这些,而在 Scala 中,您可能需要 Scalaz。

  9. Frege 默认是惰性的,但可以在必要时启用严格性,!而 Scala 默认情况下是严格的,但具有lazy用于惰性求值的关键字。

然而,作为 JVM 语言,一种语言可以从另一种语言中受益。我曾经将一个 Akka 示例移植到 Frege。最后,它归结为严格性、纯度、功能性、OO 和类型推断以及它们对您的重要性。

于 2013-07-28T19:29:35.407 回答
17

除了语法问题,最大的区别在于类型系统和执行模型。

正如@senia 已经指出的那样,scala 是严格的而不是纯函数,这并不意味着您不能编写纯函数(您也可以在 C 中这样做),只是编译器不会强制执行它。

Frege, OTOH 是懒惰和纯粹的,这意味着所有不纯的效果都被迫生活在 ST 或 IO 单子中。类型系统是 Haskell 2010 必不可少的,具有类型类和其他更高级别的函数类型。类型推断适用于整个程序,唯一的例外是具有更高级别类型的函数,其中至少必须注释多态参数。这是一个例子:

both f xs ys = (f xs, f ys)

对于这个函数,编译器推断类型:

both :: (α->β) -> α -> α -> (β, β)

请注意,两者都xs得到ys相同的类型,因为f. 但是现在假设我们想要使用一个多态列表函数,我们可以将它与不同类型的 xs 和 ys 一起使用。例如,我们想写:

both reverse [1,2,3] ['a' .. 'z']

就目前而言,这个应用程序会出错,因为这两个列表有不同的元素类型,因此也有不同的类型。所以编译器会拒绝字符列表。

幸运的是,我们可以通过类型注释更准确地告诉编译器我们想要什么:

both :: (forall e.[e] -> [e]) -> [a] -> [b] -> ([a], [b])

这告诉了以下内容:我们将传递给both一个执行一些列表转换但不关心列表元素类型的函数。然后我们传递 2 个可能具有不同元素类型的列表。我们得到一个带有我们转换列表的元组。请注意,both无需更改代码。

另一种实现相同目的的方法是编写:

both (f :: forall e.[e]->[e]) xs ys = (f xs, f ys)

类型检查器推断其余部分,即xsys必须是列表,但可以有不同的元素类型。

Scalas 类型系统(据我所知)完全支持 OO。虽然 Frege 仅部分支持为 Java 导入的类型,但不支持定义自己的类似 OO 的类型。

因此,两种语言都支持 JVM 环境中的函数式编程,尽管处于完全不同的领域。第三个利基是动态类型,Clojure 在 JVM 世界中是王者。

于 2013-07-28T08:53:42.223 回答
3

也许它跑题了,但 Scala 可用于开发 Android 应用程序(*),但 Frege 尚未成功用于此。(**)IIRC,这是因为与现有 Java 库的互操作在 Scala 中比在在弗雷格等问题中。

(*) 买者自负。我自己只做过一些小的示例程序。

(**) Frege/Java 混合已用于 Android 应用程序,但仅 Frege 的应用程序仍然不可用,AFAIK。

于 2013-08-08T14:47:27.283 回答