2011-12-24 57 views
9

我有定義瞭如下記錄:Haskell記錄中的「依賴」字段?

data Option = Option { 
    a :: Maybe String, 
    b :: Either String Int 
} deriving (Show) 

反正對我來說,強制執行,當是Nothing,B必須是Left當a是Just,B必須是Right?也許幻影類型,或其他?或者我必須將整個東西都包裹在一個Either中,並使其成爲Either String (String, Int)

+0

我不認爲Haskell 2010有什麼可以讓你在以前的解決方案。我會建議去'Either String(String,Int)',或者一個同構類型,比如'data Option = OptionA String | OptionB String Int',其中構造函數具有明智的名稱。 – 2011-12-24 17:15:48

+1

爲了最好地回答這個問題,知道附加在a和b上的*意思很重要。爲什麼有時候你沒有'a'(例如它是'Nothing')?爲什麼可以將'b'表示爲'String' *或* Int'?你爲什麼要強制執行你所談論的限制?這給了我最初的印象:「b」沒有很好的定義。 – 2011-12-24 20:08:06

回答

17

你應該只使用兩個構造兩個可能的形狀:

data Option = NoA String | WithA String Int 

當然,你應該給他們更好的名字,根據他們代表什麼。幻像類型在這裏肯定是矯枉過正,我建議避免Either - LeftRight不是很自我記錄的構造函數名稱。

如果是有意義的解釋B場的兩者或者分支機構表示相同的數據,那麼你應該定義一個反映這種解釋的功能:

b :: Option -> MeaningOfB 
b (NoA s) = ... 
b (WithA t n) = ... 

如果您有保持不變沒有字段無論選擇什麼,你都應該用它們全部創建一個新的數據類型,並將它包含在兩個構造函數中。如果您爲每個構造函數創建一條記錄,則可以在每個構造函數中爲公共字段指定相同的名稱,以便您可以從任何Option值中提取該值,而無需在其上進行模式匹配。

基本上,想想它意味着字符串不存在:它改變了關於其他領域,什麼保持不變?無論相應的施工人員有何變化,不管保持不變,都應該分解成它自己的類型。 (這是一個很好的設計原則!)

如果你來自OOP背景,你可以用構圖而不是繼承的方式來思考這個問題 - 但是儘量不要把這個比喻說得太過分。