2012-10-28 68 views
3

比方說,我們定義一個函數c sum(a, b)函數式編程風格,它返回它的參數的總和。到現在爲止還挺好;所有FP的好東西沒有任何問題。函數編程如何避免狀態,當它似乎是不可避免的?

現在我們假設我們在一個具有動態類型和單態的有狀態錯誤流的環境中運行它。那麼假設我們傳遞的值爲a和/或bsum未被設計爲處理(即不是數字),並且它需要以某種方式指示錯誤。

但是如何?這個功能應該是純粹的,無副作用的。它如何在全球錯誤流中插入錯誤而不違反該錯誤?

+2

這就是爲什麼通常純功能和動態打字不能很好地結合在一起的原因。 –

+2

@JakubHampl是嗎?即使在靜態類型語言,你仍然必須運行時錯誤(如被零除),所以我不明白怎麼會避免核心十二都在談論這個問題(但無可否認我還沒有完全理解這個問題) 。核心Xii:什麼是錯誤流? – sepp2k

+0

@ sepp2k在這個問題的上下文中,「錯誤流」是一些報告錯誤的全局系統機制,比如std.err,異常等;通常是帶外的,但不是必需的。 –

回答

9

沒有編程語言,我知道有什麼像內置的「單身狀態錯誤流」,所以你必須做一個。如果你試圖用純粹的功能風格來編寫你的程序,你只需就不會做出這樣的事情。

但是,您可以使用sum函數返回總和或錯誤指示。實際上這種類型實際上通常以名稱Either而知道。然後,您可以輕鬆地創建一個調用可能返回錯誤的大量計算的函數,並返回其他計算中遇到的所有錯誤的列表。這與你所談論的非常接近;它只是顯式返回而不是全局。請記住,當你編寫一個功能程序時,問題是「如何製作一個具有我想要的行爲的程序?」不是,「我將如何複製在另一種編程風格中採用的一種特定方法?」。 「全局狀態錯誤流」是意味着而不是結束。您不能在純函數樣式中使用全局狀態錯誤流,否。但問問自己,你使用全局狀態錯誤流實現;不管它是什麼,你可以實現在函數式編程中,只是沒有相同的機制。

詢問純函數式編程是否可以實現一種依賴於副作用的特定技術,就像詢問如何使用面向對象編程中的彙編技術。面向對象提供不同的工具供您用來解決問題;限制自己使用這些工具來模擬不同的工具集並不是一種有效的方法。


在迴應評論:如果你想實現與您的錯誤流記錄錯誤消息到終端的東西,那麼是的,在一定程度上的代碼將不得不做的IO去做。

打印到終端就像其他任何IO一樣,沒有什麼特別的特別之處,它使得它值得挑選出來,因爲狀態似乎特別不可避免。因此,如果這會將您的問題變成「純粹的功能性程序如何處理IO?」,那麼無疑有許多重複的問題,更不用說很多博客文章和教程正是針對這個問題。對於純編程語言的實現者和使用者來說,這不是一個突然的驚喜,這個問題已經存在了數十年了,並且已經有一些非常複雜的想法被應用於答案中。

在不同的語言中有不同的方法(在Haskell中有IO monad,在水星中有獨特的模式,在Haskell的歷史版本中有懶惰的請求和響應流等)。其基本思想是提出一個可由純代碼操作的模型,並將模型的操作與語言實現中的實際不純操作聯繫起來。這可以讓你保持純度的好處(適用於純代碼的證據,但不適用於普通的不純代碼仍然適用於使用純IO模型的代碼)。

純模型必須小心設計,使你不能真正用它做任何事情沒有意義,在實際IO方面。例如,水星確實IO具有你寫的程序你繞過宇宙的當前狀態彷彿作爲一個額外的參數。這個純粹的模型準確地表示了依賴於並影響程序之外的宇宙的操作的行爲,但只有當系統中的任何一個時刻都有一個宇宙狀態時,它纔會貫穿整個程序,從頭到尾。所以有一些限制

  1. 類型io是抽象的,所以沒有辦法構造該類型的值;唯一的辦法就是從你的調用者那裏得到一個。一個io的值通過語言實現傳遞給main謂詞,以完成整個事情。
  2. 傳遞給mainio值的方式聲明,這樣它是獨一無二的。這意味着你不能做可能導致它重複的事情,比如將它放在一個容器中,或者將相同的io值傳遞給多個不同的調用。獨特的模式可確保當你經過它一旦值是「死」的,不能被其他任何地方通過您只能在io值個屁也採用了獨特的模式的謂詞,並儘快。

注意,即使在必要的程序,你獲得了很大的靈活性,如果你有你的錯誤日誌記錄系統返回的錯誤信息流,然後只實際上使打印這些接近決策程序的最外層。如果您的日誌呼叫被直接立即以書面形式輸出,這裏只是幾件事情,我能想到的把我的頭頂部是變得更難有這樣一個系統來做:

  • 預測執行的計算,看看是否它未能通過檢查是否它發出的所有錯誤
  • 將多個高級別系統到一個單一的系統中,添加標記日誌以每個系統區分
  • 的Emit調試且僅當還存在一個錯誤消息信息登錄消息(所以輸出是乾淨的,當有調試任何錯誤,並含有豐富的細節時,有)
+0

我明白你的意思了,但讓我們假設系統有一個終端來打印信息。某處,_some_代碼必須觸及這個全局狀態的對象,不是? –

+1

@CoreXii是的,一些必要的位本質上是不純的。我建議你閱讀Simon Peyton Jones的[解決笨拙的小隊](http://research.microsoft.com/en-us/um/people/simonpj/papers/marktoberdorf/)。雖然細節現在已經過時,但對於Haskell如何解決這些問題,這是一個非常可讀的闡述。其他語言使用不同的方法(我聽說過的關鍵字:唯一性打字,效果系統),但我沒有資格談論這些。 – delnan

+0

@CoreXii我在回答中增加了一些更多的散漫內容,希望能夠解決您的問題。 – Ben