2010-12-12 39 views
12

讀「真實世界哈斯克爾」我發現有關數據類型的一些intresting問題:哈斯克爾的數據類型使用情況良好practicies

這種模式匹配和位置 數據訪問使它看起來像你的數據之間 非常緊耦合和 對其進行操作的代碼(嘗試將 添加到Book中,或者更糟糕地改變現有部件的 類型)。

這通常是 勢在必行(特別OO)一個非常糟糕的事情 語言...它不被視爲在Haskell一個 問題? source at RWH comments

真的,寫一些Haskell程序我發現,當我做小改動的數據類型結構也影響使用該數據類型的幾乎所有功能。也許有一些數據類型使用的良好做法。我怎樣才能最小化代碼耦合?

回答

13

您所描述的內容通常稱爲表達問題 - http://en.wikipedia.org/wiki/Expression_Problem

要做出明確的權衡,一般來說,haskell代碼,特別是代數數據類型,傾向於難以改變類型,但易於在類型上添加函數。這優化了(預先)精心設計的完整數據類型。

說了這麼多,你可以做很多事情來減少耦合。

  • 定義良好的庫函數,定義了一套完整的組合程序和高階函數類型,你會減少耦合是有用的與您的數據交互。人們經常說,當你想到模式匹配時,使用高階函數會有更好的解決方案。如果你尋找這些情況,你將會處在一個更好的位置。

  • 將您的數據結構暴露爲更多抽象類型。這意味着實施所有適當的類型類。這將有助於定義一個庫函數,因爲您可以通過任何實現的類型類免費獲得一堆函數,例如查看對Functor或Monad的操作。

  • 隱藏(儘可能)任何類型的構造函數。構造函數公開實現細節並鼓勵耦合。提示:這個鏈接定義了一個與你的類型交互的好api,你的類型的消費者應該很少使用類型構造函數。

Haskell的社會似乎在這個特別好,如果你看很多的庫上hackage你會發現實現類型類和暴露好的庫函數的真正的好例子。

+0

我不認爲你沒有模式匹配就可以相處。 *顯式遞歸*然而很少需要。 – delnan 2010-12-12 11:50:33

+0

+1給野獸一個名字。 – fuz 2010-12-12 12:25:03

7

首先,我想提一提,在我看來,有兩種接頭:

  • 那個能夠使你的代碼停止時,你改變一個編譯和忘記改變其他

  • 那個能夠使你的代碼馬車當你改變一個忘記改變對方

雖然兩者都是有問題的,前者是顯著少的啊eadache,這似乎是你正在談論的那個。

我認爲你提到的主要問題是由於過度使用位置參數。 Haskell幾乎強迫你在普通函數中有位置參數,但是你可以在你的類型產品(記錄)中避免它們。

只需在數據構造函數中使用記錄而不是多個匿名字段,然後就可以通過名稱與任何你想要的字段進行模式匹配。

bad (Blah _ y) = ...

good (Blah{y = y}) = ...

避免過度使用元組,尤其是那些超過2元組,並自由創造的記錄/乾坤newtypes以避免位置的含義。

+1

謝謝你的回覆。我不是很喜歡記錄語法,因爲字段名稱在模塊中變成全局的。也許有一些治療方法? – aindl 2010-12-12 11:34:15

+0

IMO的治療方案有很小的模塊:-) – Peaker 2011-01-06 21:14:22

+0

@masterzim記錄中的命名空間污染問題將在GHC即將發佈的版本中得到一個修補程序,這將允許您爲幾種類型提供相同的記錄名稱,免費獲得將是具有該記錄字段的類型的一般性內容。 – kqr 2013-12-15 15:13:20

10

除了什麼有人說:

一個有趣的方法是定義了數據類型功能的「scrap your boilerplate」的風格,這使得使用泛型函數(而不是明確的模式匹配)來定義過的功能數據類型的構造函數。查看「廢棄樣板」文件,您將看到可以應對數據類型結構變化的函數示例。

的第二種方法,如Hibberd指出的那樣,是使用摺疊映射展開,和其它遞歸組合程序,來定義函數。當您使用高階函數編寫函數時,通常可以在Functor,Foldable等的實例聲明中處理底層數據類型的小改動。