私のHaskellプロジェクトには式評価器が含まれています。これは、この質問の目的のために次のように簡略化できます。
data Expression a where
I :: Int -> Expression Int
B :: Bool -> Expression Bool
Add :: Expression Int -> Expression Int -> Expression Int
Mul :: Expression Int -> Expression Int -> Expression Int
Eq :: Expression Int -> Expression Int -> Expression Bool
And :: Expression Bool -> Expression Bool -> Expression Bool
Or :: Expression Bool -> Expression Bool -> Expression Bool
If :: Expression Bool -> Expression a -> Expression a -> Expression a
-- Reduces an Expression down to the simplest representation.
reduce :: Expression a -> Expression a
-- ... implementation ...
これを実装する簡単な方法は、次のcase
ように、再帰的に評価してパターン マッチする式を記述することです。
reduce (Add x y) = case (reduce x, reduce y) of
(I x', I y') -> I $ x' + y'
(x', y') -> Add x' y'
reduce (Mul x y) = case (reduce x, reduce y) of
(I x', I y') -> I $ x' * y'
(x', y') -> Mul x' y'
reduce (And x y) = case (reduce x, reduce y) of
(B x', B y') -> B $ x' && y'
(x', y') -> And x' y'
-- ... and similarly for other cases.
私には、その定義はややぎこちないように見えるので、次のようにパターン ガードを使用して定義を書き直しました。
reduce (Add x y) | I x' <- reduce x
, I y' <- reduce y
= I $ x' + y'
この定義は、式に比べてきれいに見えると思いますcase
が、異なるコンストラクターに対して複数のパターンを定義すると、パターンが複数回繰り返されます。
reduce (Add x y) | I x' <- reduce x
, I y' <- reduce y
= I $ x' + y'
reduce (Mul x y) | I x' <- reduce x
, I y' <- reduce y
= I $ x' * y'
これらの繰り返されるパターンに注目して、パターン マッチングの繰り返しを削減できる構文または構造があることを期待していました。これらの定義を単純化する一般的に受け入れられている方法はありますか?
編集:パターン ガードを確認した後、ここでドロップインの代わりとして機能しないことに気付きました。とを に縮小できる場合は同じ結果にx
なりますが、パターン ガードが一致しない場合は値を縮小しません。et al.の部分式を単純化したいと思います。y
I _
reduce
Add