Scala和Frege都是针对JVM的类型化函数语言。
Frege离Haskell更近,Scala有更独立的历史。
但是如果我们不看语法差异,那么两种允许的编程技巧,风格,概念有什么不同呢?
答案 0 :(得分:41)
恕我直言,两者都是非常好的语言,但就范式而言,Scala比Frege更好OO,但Frege的功能优于Scala。关于差异,它主要归结为Haskell vs Scala,因为Frege(或几乎看到Haskell和Frege here之间的差异)Haskell用于JVM。
Frege的类型推断是全局的,因此我们不必像在Scala(本地推断)中那样经常注释类型。
在Frege中,模块只是类型和函数的命名空间,而Scala有更好的模块系统。 http://2013.flatmap.no/spiewak.html
在Frege中,默认情况下函数是curry,因此不需要为部分函数应用程序添加其他构造。部分类型构造函数应用程序也是如此。
在弗雷格,没有def
vs val
,一切都是功能。因此,函数比Scala更加一流。
Frege没有子类型,但类型系统会在本机调用中找出子类型。例如,您可以将ArrayList
传递给需要Java List
的函数。
由于没有子类型,因此在Frege中我们现在无法扩展Java类或实现接口(将来可能会支持)所以我们需要一个可以扩展/实现的Java类,但方法实现将是从弗雷格作为职能部门传递。
从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)
由于这些函数会使对象变异,因此它们必须位于ST
monad中。另请注意,此处Frege还处理null
方法返回的get
,因为它使用Maybe
类型进行注释。 null
通过本地接口的唯一方法是通过本地接口,因为Frege没有null的概念。
另一个例子:
pure native floor Math.floor :: Double -> Double
表示该函数是纯函数,因此签名直接反映了没有IO
或ST
的原始Java签名。
Frege没有Scala的var
中的变量和副作用
通过类型更明确。 (只是没有null
,没有var
和明显的副作用使Frege更有趣,至少对我而言。从某种意义上说,Frege,就像Haskell一样,是一种“精细命令式编程语言”,适用于JVM !)
作为一个Haskell方言,Frege对Functors,Applicatives,Monads和其他功能“模式”更自然,并且有标准库中的那些,而在Scala中,你可能需要Scalaz。
默认情况下,Frege是惰性的,但必要时可以通过!
启用严格性,而默认情况下Scala是严格的,但是对于延迟评估有lazy
个关键字。
然而,作为JVM语言,一种语言可以从其他语言中受益。我曾经移植过Akka example to Frege。最后,它归结为严格性,纯度,功能,OO和类型推断以及它们对您有多重要。
答案 1 :(得分:17)
除了语法问题,最大的区别在于类型系统和执行模型。
正如@senia已经指出的那样,scala是严格的而不是纯粹的,这并不意味着你不能编写纯函数(你也可以在C中编写),只是编译器不会强制执行它。
Frege,OTOH是懒惰和纯粹的,这意味着所有不纯净的效果都被迫生活在ST或IO monad中。类型系统对于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)
并且类型检查器推断其余部分,即xs
和ys
必须是列表,但可以具有不同的元素类型。
Scalas类型系统完全(据我所知)支持OO。虽然Frege仅部分支持为Java导入的类型,但不支持定义类似OO的类型。
因此,两种语言都支持JVM环境中的函数式编程,尽管它们完全不同。第三个利基是动态类型的,其中Clojure是JVM世界中的王者。
答案 2 :(得分:3)
也许这不是主题,但Scala可以用来开发Android应用程序(*),但是Frege还没有被成功地用于那个。(**)IIRC,这是因为与现有Java库互操作要容易得多在斯卡拉比弗雷格,以及其他问题。
(*)警告。我自己只做过小的示例程序。
(**)Frege / Java混合已用于Android应用程序,但仅限Frege的应用程序仍无法使用,AFAIK。