レンズとデフォルトのインスタンスの組み合わせをお勧めします。モジュールの半分をまだインポートしていない場合はControl.Lens
、今が開始するときです。とにかく、レンズとは一体何ですか?レンズは、ゲッターとセッターを 1 つの関数にマッシュしたものです。そして、それらは非常に構成可能です。データ構造の一部にアクセスしたり変更したりする必要があるが、レコード構文が扱いにくいと思うときはいつでも、レンズが役に立ちます。
したがって、最初に行う必要があるのは、TH と import を有効にすることですControl.Lens
。
{-# LANGUAGE TemplateHaskell #-}
import Control.Lens
データ型に必要な変更は、次のようにすべてのフィールドに名前を追加することです。
data SpecialDslExpression = MyExpression { _exprType :: String
, _exprParams :: [Int]
, _exprCost :: Double
, _exprComment :: [String]
, _exprLog :: Maybe Bool
} deriving Show
次の手順では、フィールド名の先頭にあるアンダースコアが重要です。フィールドのレンズを生成したいからです。Template Haskell を使って、GHC にそれを依頼することができます。
$(makeLenses ''SpecialDslExpression)
次に、最後に行う必要があるのは、「空の」インスタンスの構築です。必要なフィールドがすべて実際に入力されていることを静的にチェックする人は誰もいないことに注意してくださいerror
。少なくとも実行時エラーが発生するように、これらのフィールドに を追加することをお勧めします。このようなもの:
emptyExpression = MyExpression (error "Type field is required!") [] 0.0 [] Nothing
これで準備完了です。を使用することはできずemptyExpression
、実行時に失敗します。
> emptyExpression
MyExpression {_exprType = "*** Exception: Type field is required!
しかし!タイプフィールドにデータを入力する限り、あなたはゴールデンになります:
> emptyExpression & exprType .~ "Test expression"
MyExpression { _exprType = "Test expression"
, _exprParams = []
, _exprCost = 0.0
, _exprComment = []
, _exprLog = Nothing
}
必要に応じて、一度に複数のフィールドに入力することもできます。
> emptyExpression & exprType .~ "Test expression"
| & exprLog .~ Just False
| & exprComment .~ ["Test comment"]
MyExpression { _exprType = "Test expression"
, _exprParams = []
, _exprCost = 0.0
, _exprComment = ["Test comment"]
, _exprLog = Just False
}
レンズを使用して、関数をフィールドに適用したり、フィールドのフィールド内を調べたり、他の既存の式を変更したりすることもできます。何ができるか見てみることをお勧めします!