Scrap Your BoilerplateやHaskellでのジェネリック プログラミングについて話している人を見かけます。これらの用語はどういう意味ですか? Scrap Your Boilerplate を使用するのはいつで、どのように使用すればよいですか?
1 に答える
多くの場合、複雑なデータ型を変換するときは、構造の小さな部分に影響を与えるだけで済みます。つまり、特定の簡約可能な式 (redex) のみを対象としています。
古典的な例は、整数式の型に対する二重否定の除去です。
data Exp = Plus Exp Exp | Mult Exp Exp | Negate Exp | Pure Int
doubleNegSimpl :: Exp -> Exp
doubleNegSimpl (Negate (Negate e)) = e
...
...
この例を説明する場合でも、パーツ全体を書き出すことは避けたいと思います。これは完全に機械的ですExp
。.
この「エンジン」は、私たちが廃棄しようとしているボイラープレートです。
これを実現するために、Scrap Your Boilerplate は、データ型に対して「一般的なトラバーサル」を構築できるメカニズムを提案しています。これらのトラバーサルは、問題の特定のデータ型について何も知らなくても正確に動作します。これを行うために、非常に大まかに言えば、一般的な注釈付きツリーの概念があります。これらは、すべての ADT を注釈付きツリーのタイプに投影できるように、ADT よりも大きくなります。
section :: Generic a => a -> AnnotatedTree
「有効な」注釈付きツリーは、ADT のブランドに投影することができます。
retract :: Generic a => AnnotatedTree -> Maybe a
特に、型クラスを導入して、定義済みのGeneric
型を示します。section
retract
すべてのデータ型のこの一般的な注釈付きツリー表現を使用して、トラバーサルを一度だけ定義できます。特に、エンドユーザーが型にさらされることがないように、(戦略的に使用して)section
インターフェースを提供します。代わりに、次のようになります。retract
AnnotatedTree
everywhere' :: Generic a => (a -> a) -> (AnnotatedTree -> AnnotatedTree)
final と initialsection
およびretract
s と、注釈付きツリーが常に「有効」であるという不変条件と組み合わせて、
everywhere :: Generic a => (a -> a) -> (a -> a)
everywhere f a0 = fromJust . retract . everywhere' f . section
何をしeverywhere f a
ますか?f
ADT の「どこでも」関数を適用しようとしますa
。言い換えれば、二重否定の単純化を次のように書きます。
doubleNegSimpl :: Exp -> Exp
doubleNegSimpl (Negate (Negate e)) = e
doubleNegSimpl e = e
つまり、id
redex(Negate (Negate _))
が一致しない場合は常に として機能します。これに当てはめeverywhere
てみると
simplify :: Exp -> Exp
simplify = everywhere doubleNegSimpl
次に、一般的なトラバーサルを介して「どこでも」二重否定が排除されます。...
ボイラープレートはなくなりました。