2011-12-24 10 views
9

私は定義された以下のレコードを持っている:私はNothingあるとき、bはLeftJustあるとき、bはRightでなければならなければならないことを強制するためにレコードのHaskell "dependent"フィールド?

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

はとにかくありますか?たぶん、ファントムの種類、または何か他の?または、私は全体の中を包み込み、それをEither String (String, Int)にする必要がありますか?

+0

私はHaskell 2010にこれまでのソリューションでこれを許可するものはないと思います。私は、 'String(String、Int)'か、 'data Option = OptionA String | 'のような同形の型を使うことをお勧めします。 OptionB String Int'を返します。コンストラクタには分かりやすい名前があります。 –

+1

これに最もよく答えるためには、「a」と「b」に付いている*意味*を知ることが重要です。なぜあなたは 'a'を持っていないのですか?(例えば' Nothing'ですか?) 'b'を' String' *または 'Int'のどちらかと表現するのはどうですか?なぜあなたが話していた制限を強制したいのですか?これは、「b」が明確に定義されていないという初期の印象を与える。 –

答えて

17

あなたはちょうど2つの可能な形状のために2つのコンストラクタを使用する必要があります。

data Option = NoA String | WithA String Int 

もちろん、あなたは彼らが何を表しているかに基づいて、より良い名前を与える必要があります。ファントムタイプはここでは間違いなく残念ですが、私はEither - LeftRightということはあまり自己文書化するコンストラクタ名ではないことを避けることをお勧めします。

それは同じデータを表すものとしてBフィールドの両方のいずれかの枝を解釈することは理にかなっている場合、あなたはこの解釈を反映した機能定義する必要があります:あなたは同じなし滞在フィールドを持っている場合は

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

は、どのような選択肢か、それらのすべてを使って新しいデータ型を作成し、それを両方のコンストラクタに含める必要があります。各コンストラクターをレコードにする場合は、すべてのコンストラクターで共通フィールドに同じ名前を付けることができます。したがって、パターンマッチングなしでOptionの値から抽出できます。

基本的に、それについて考えてみましょうは、文字列が存在しないことを意味します。他のフィールドについては何が変わりますか?それぞれのコンストラクタにどのような変更を加える必要がありますか。同じものにとどまるものは、それ自体のタイプに分解されるべきです。

OOPの背景から来た場合は、継承ではなく合成による推論という点で考えることができますが、あまりにも遠すぎるとは思わないようにしてください。

関連する問題