2013-03-11 131 views
2

下面是在其中一個答案提出的申索:https://softwareengineering.stackexchange.com/a/136146/18748爲什麼在函數式編程中計算速度更快/效率更高?

試試你的手在功能性語言或兩個。嘗試使用遞歸執行 因子在二郎山,看你的下巴砸在地板上 時20000! 5秒內返回(站點沒有堆棧溢出)

爲什麼它比在Java/C/C++/Python(any)中使用遞歸/迭代更高效?什麼是使這種情況發生的基礎數學/理論概念?不幸的是,我從未接觸過我的本科生的函數式編程(從'C'開始),所以我可能只是不知道'爲什麼'。

+0

主持人:如果認爲不合適,請將其移至合適的論壇/網站。 – PhD 2013-03-11 22:31:56

+2

http://en.wikipedia.org/wiki/Tail-call_optimization – 2013-03-11 22:32:17

+4

這不是更快,這是hogwash。然而,_write_通常更快。 – 2013-03-11 22:33:32

回答

2

遞歸的解決辦法可能是在Java或C++慢,笨重,但我們沒有做的事情在Java和C++這樣,所以。 :)

至於爲什麼,函數式語言總是會使用非常繁重的遞歸(因爲默認情況下,它們必須跳過箍環,或者根本不允許修改變量,這些變量本身會使大多數形式的迭代無效或完全不可能)。所以他們必須有效地優化它,才能具有競爭力。

幾乎所有的人實施所謂的「尾調用消除」的優化,它採用了下一次調用當前調用的堆棧空間並打開「呼叫」變成了「跳躍」。這個小小的變化基本上將遞歸轉化爲迭代,但不提醒FPer。當涉及程序語言的迭代和功能性的遞歸時,兩者將證明性能相當。 (如果其中任何一個仍然更快,但它會迭代。)

其餘的是庫和數字類型等。體面的數學代碼==>體面的數學表現。沒有什麼保持程序或面向對象的語言,從同樣的優化,除此之外大多數人不想那麼多。另一方面,功能程序員喜歡臍眼,他們很容易計算斐波納契數列和20000!以及我們大多數人永遠不會使用的其他數字。

1

Tail-call optimization

Lazy evaluation:「當使用延遲評價,表達不只要它被綁定到變量評價,但是當評價者被強制以產生表達式的值」

這兩個概念在本question about various ways of implementing factorial in Clojure示出。您還可以在Stuart Halloway和Aaron Bedra的書Programming Clojure中找到關於懶惰序列和TCO的詳細討論。

以下功能,從編程的Clojure通過,創建與斐波那契數序列的第一1M成員懶惰序列,實現了一個十萬分之一構件:

user=> (time (nth (take 1000000 (map first (iterate (fn [[a b]] [b (+ a b)]) [0N 1N]))) 100000)) 
"Elapsed time: 252.045 msecs" 
25974069347221724166155034.... 
(20900 total digits) 

(512MB堆,英特爾酷睿i7 ,2.5GHz的)

+0

請注意,儘管Clojure是一種嚴格(不懶惰)的語言,並且不會實現完整的尾部調用優化,因爲它在JVM上運行... – 2013-03-11 23:16:00

+0

在JVM上,您必須僞裝它',直到您使用[ lazy-seq](http://clojuredocs.org/clojure_core/clojure.core/lazy-seq)和[recur](http://clojuredocs.org/clojure_core/clojure.core/recur) – 2013-03-11 23:27:20

+0

@DonStewart For factorial,你不需要全面的TCO,只需要尾部遞歸消除。我無法想象Clojure不這樣做。 – Ingo 2013-03-12 00:52:58

1

快(比什麼?),並且它與尾部呼叫優化無關(僅在這裏引入流行詞是不夠的,還應該解釋爲什麼尾部呼叫優化應該比循環更快),但事實根本不是這樣!

請注意我不是一個功能性編程仇恨,相反!但是傳播神話並不適用於函數式編程。

順便說一句,這裏有任何一個實際上嘗試需要多長時間來計算(和打印,這應該消耗至少50%的CPU週期所需)20000!?

我所做的:

main _ = println (product [2n..20000n]) 

這是一個JVM語言編譯成Java,它使用Java大整數(已知慢)。它也遭受JVM啓動成本的影響。這並不是最快的方法(例如顯式遞歸可以節省列表構造)。

結果是:

181920632023034513482764175686645876607160990147875264 
... 
... many many lines with digits 
...   
000000000000000000000000000000000000000000000000000000000000000 

real 0m3.330s 
user 0m4.472s 
sys  0m0.212s 

(在英特爾®酷睿™i3 CPU中號350 @ 2.27GHz×4)

我們可以安全地假設,同樣用C符合GMP不會甚至可以使用這個時間的50%。

因此,官能更快是神話,以及官能較慢。這甚至不是一個神話,只要人們沒有說比較快/慢就說不出來。

+0

原文中提到的語言是「Java,C/C++,JavaScript/jQuery和... Objective-C」。我的觀點是,TCO和/或懶惰評估是Clojure的特性,可以支持在其他環境中可能證明具有挑戰性的非常大的計算。我已經提供了一個例子,就像OP的鏈接文章中的其他例子一樣。 – 2013-03-12 03:18:54

相關問題