2016-04-22 10 views
2

12個の値を持つレコードがあります。有効でない値の組み合わせがいくつかありますので、コンストラクタでこれを確認してください。私は引数のリストを取るコンストラクタを作る方法しか知りませんが、それは12の値ではあまりよくありません。したがって、値を使用した後でレコード構文を使用したいと考えています。レコードの構文:コンストラクタの内容を検証します

コンストラクタに制約を適用し、レコード構文を使用するにはどうすればよいですか?

+0

「青写真」を使用する方法もあります。青写真のコンストラクタを開いて未検証にし、実際のデータコンストラクタを 'Blueprint - > ActualData'関数の後ろに隠します。 –

+0

よく**あなたはあなたのモジュールからコンストラクタを公開するために** not **を選択し、条件をチェックしてそれを公開するスマートコンストラクタ*(関数)を使用して – Carsten

+1

@Carstenを呼び出すことができますが、私はここで主なポイントだったと思います。 –

答えて

5

私は最初のコメントをもう少し精巧な方法で投稿しますが、これで十分です。

まずは、あなたのデータは、多かれ少なかれ、このようになりますと仮定してみましょう:スマートコンストラクタに置き換えたときに

data MyBigData = MyBigData { 
    a :: ... 
    b :: ... 
    ... 
    z :: ... 
} 

は確かに、あなたはその問題について多くを行うことはできません。

しかし、あなたのライブラリ関数は次のように多かれ少なかれ見えると仮定:

libFun :: MyBigData -> Result 

私は、次の解決策を提案します。ラップタイプを作成します。

newtype ValidData = ValidData MyBigData 

コンストラクタをエクスポートしないでください。あなたの機能を変更します。

libFun :: ValidData -> Result 
libFun (ValidData d) = ... 

と機能における検証ロジック置く:validateを呼び出すときに、レコード構文を使用することができますが、あなたがこのデータを使用することはできません今

validate :: MyBigData -> Maybe ValidData 

を最初にそれを検証しないと、実際にコヒーレントな状態でそれを期待する関数。もちろん

input = validate $ MyBigData { ... } 
case input of: 
    Just d -> libFun d 
    Nothing -> ... 

この場合validateEitherを返すか、おそらくあなたがそれを必要とする場合monadically作用することができます。

+0

それに加えて、もしあなたがそのようなデータ型を複数持っているなら、おそらく 'DataFamilies'のための良い場所になるかもしれません。 'origType = a''、' validType :: Valid a'、 'validate :: a - > Valid a'で一般的な' newtype Valid a = Valid a'と 'class Validable'を作成します。それがうまくいくか、それが買うだろうとは確信していませんが、おそらく探求しています。 –

+0

モジュールを_extensible_にするにはどうすればいいですか?つまり、モジュールのユーザーが、 'libFun'の定義のようなパターンでコンストラクタ' ValidData'を使用することを許可します。 'ghc'は次のように文句を言う:'非有効範囲:データコンストラクタ 'ValidData'' –

+0

@HansLub 'libFun'の定義は、これが有効なデータで動作するライブラリ関数であることを特に意味しました。しかし、その場合、 'ValidData - > MyBigData'は常に安全であるため、他の答えと同様に抽出関数をエクスポートすることもできます。 –

2

私はちょうど「捨て」些細な機能

section :: ActualData -> Blueprint 

との組み合わせで、オープンで未検証のコンストラクタで補助データ型Blueprintを使用するようにBartek Banachewiczの提案を使用して、ActualDataスマートコンストラクタfromBluePrint :: Blueprint -> ActualDataう検証 -

fromBlueprint . sectionActualDataのアイデンティティであることを意味 セクション右逆ため another nameです)

さて、あなたはviewPatternsを使用してActualData(または[ActualData]ような、より複雑な種類の上で関数を定義するときにビューを入れ子にすることができるよう、タイプActualDataの値を構築するにしてパターンでレコード構文を使用して

x :: ActualData 
x = fromBlueprint $ Blueprint {a=1, b="baz",...} 

f :: ActualData -> Int 
f (section -> Blueprint{a=x}) = 2*x 

ようなコードを書くことができます)

+0

関連項目:[パブリックデータ型で制約を適用できますか?](http://stackoverflow.com/questions/23893351/can-constraints-be-enforced-on-public-data-types/23893832#23893832) –

関連する問題