Scala vs F#:函數式編程特性大比拼(一)
原創【51CTO獨家譯文】我們喜歡把.NET和Java拿出來進行比較:從測試速度到安全性,從平臺之爭到應用廣泛性。而Scala和F#都是相對較新的編程語言,相對于.NET和Java編程語言,它們提供了許多非常吸引人的函數式編程特性,值得.NET和Java開發人員仔細玩味和評估。
Scala是一種基于Java的通用編程語言,旨在推廣函數式編程,它編譯成Java字節碼,在Java虛擬機(JVM)上運行。雖然Scala本質上是一個函數式編程語言,但它也體現了面向對象語言的所有必要元素,這一點使函數式編程特性對編程社區的吸引力更大。
51CTO編輯推薦:Scala編程語言專題
F#是由微軟主持開發的一個通用編程語言,它是.NET通用運行時(CLR)的一部分,它是以另一個正統的函數式編程語言Ocaml為基礎的,微軟在.NET平臺中引入F#除了人們對函數編程的興趣不斷上升外,另一個重要的原因是函數編程非常適合高性能和并行計算。雖然它的語法清晰,但F#實際上混合了函數式編程語言,命令式語言和面向對象語言的語法特性,它的面向對象和命令式特性大部分都與.NET平臺兼容,F#的三重性質也很實用,它允許程序員使用任意結合這三個編程語言的特性使用。
51CTO編輯推薦:F#函數式編程語言專題
本文將對Scala和F#功函數編程語法和相關特性進行對比,看看它們之間有何異同點。
一等函數
Scala和F#中的函數被視為一等類型,它們可以作為參數傳遞,從其它函數返回值,或分配給一個變量。
在下面的F#代碼片段中,我首先定義了一個函數(increment),給傳遞來的值加1,然后,我定義了函數handler,它使用類型myfunc,使用2作為它的參數,最后,我使用一個遞增的參數調用這個函數處理程序,函數increment作為一個有規則的值傳遞,因此它被認為是一等類型。
- let increment xx = x + 1
- let handler myfunc = (myfunc 2)
- printfn "%A" (handler increment)
注意上述代碼中的類型推斷,F#將會推斷x是一個整型(int),因為我給它加了1,下面是使用Scala語法編寫的代碼:
- def increment(x:Int) = x + 1
- def handler( f:Int => Int) = f(2)
- println( handler( increment ))
懶散式賦值
F#支持懶散式賦值(lazy evaluation),但由于性能原因,這項特性默認并沒有開啟,相反,F#支持所謂的主動賦值(eager evaluation),用關鍵字lazy明確標記函數為懶散函數,運行程序時指定Lazy.fore選項。
- let lazylazyMultiply = lazy ( let multiply = 4 * 4 )
和F#一樣,Scala默認也不支持懶散賦值,但和F#不一樣的是,Scala是用lazy關鍵字標記值,而不是標記函數。
- def lazyMultiply(x: => y:) = { lazy val y = x * x }
#p#
局部套用函數
局部套用函數是函數式編程語言的基本功能,允許應用程序的部分函數和操作組合,F#支持局部套用函數,下面是F#中局部套用函數的一個示例。
聲明:
- val add : int -> int -> int
實現:
- let add = (fun x -> (fun y -> x + y) )
在Scala中,局部套用函數的樣子有所不同:
- def add(x:Int)(y:Int) = x + y
Lambda表達式
F#也支持Lambda表達式(匿名函數),在F#中,Lambda表達式是使用關鍵字fun聲明的,在下面的例子中,一個匿名函數應用給一串遞增的數字,返回一串新的遞增數字。
- let list = List.map (fun i -> i + 1) [1;2;3]
- printfn "%A" list
Scala中的Lambda表達式非常時尚簡潔,下面是用Scala語法重寫的代碼:
- val list = List(1,2,3).map( x => x + 1 )
- println( list )
模式匹配
模式匹配是函數式編程語言的一個強大功能,可根據值或表達式的類型激活函數中的代碼塊(可將模式匹配看作是功能更強大的case語句)。
在F#中,使用垂直分隔符(|)表示一個case選擇器,下面是Fibonacci(斐波納契)數字函數的F#實現。
- let rec fib n =
- match n with
- | 0 -> 0
- | 1 -> 1
- | 2 -> 1
- | n -> fib (n - 2) + fib (n - 1)
和F#一樣,Scala也支持模式匹配,下面是Fibonacci(斐波納契)數字函數的Scala實現,注意Scala使用了case關鍵字。
- def fib( n: Int): Int = n match {
- case 0 => 0
- case 1 => 1
- case _ => fib( n -1) + fib( n-2)
- }
列表推導
最初出現在Haskell(另一個函數式編程語言原型)中,列表推導是數學術語,使用基于符號的表達式定義列表,例如,在Haskell中,使用以下列表推導生成一串只包含大于2的數字的平方值。
- squares = [ x*x | x <- nums, x > 2 ]
F#中與列表推導相同的功能叫做發生器,它既可用于列表也可用于序列,在函數式編程語言中,序列與列表類似,但序列中的元素是在請求時才計算出來的(如,1…1000),存儲效率更好。
列表發生器的格式如下:
- [for x in collection do ... yield expr]
序列發生器的格式如下:
- seq {for x in collection do ... yield expr}
因此前面的Haskell列表推導示例用F#語法重寫后,就應該是:
- del list = [for x in 0..100 if x > 2 do yield x*x]
在Scala中,列表推導的結構如下:
- val type = for ( range ) [if (condition)] ) yield result
下面是用Scala語法重寫后的版本:
- val list = for (i <- 1 to 100; if (i > 2)) yield i*i
通過混合實現多重繼承
F#和Scala之間一個最明顯的區別是F#不支持多重繼承,在Scala中,程序員可以從主類聲明子類擴展,也可以繼承其它類的特性。
在所謂的混合類中,子類通過mixin繼承,在下面的例子中,OtherParentClass就被用作mixin。
- Class MixinSubclass extends BaseClass with OtherParentClass
基類使用extends關鍵字聲明,混合則使用with關鍵字聲明。
繼承的方法使用關鍵字override明確覆蓋以防發生意外。
- override def calculate(dx: Int, dy: Int): Distance =
- new Distance(x + dy, y + dy )
OtherParentClass應該使用關鍵字trait聲明:
- trait OtherParentClass
- def count:Int
- def kmDistance = count * 1.66
小結
除了Scala混合功能外,F#和Scala提供的功能都很相似,它們都非常靈活,都是很強大的函數式編程語言,本文只對這兩個編程語言最基本的編程功能做了簡略的比較,在下一篇文章中,我將會比較它們的最大不同點:應用程序開發模型和運行時功能。
原文出處:www.developer.com/features
原文名:Scala vs. F#: Comparing Functional Programming Features
作者:Edmon Begoli
【51CTO譯稿,非經授權謝絕轉載,合作媒體轉載請注明原文出處、作者及51CTO譯稿和譯者!】
【編輯推薦】
- Scala vs F#:函數式編程特性大比拼(二)
- Scala:Java+函數式=后函數式?
- F#終于支持Silverlight 4 四大新特性一覽
- Scala代碼編寫中常見的十大陷阱
- F#中關于代理的基本使用
- 最容易令初學者混亂的F#命令



















