В моем проекте 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
и y
могут быть уменьшены до I _
, они не уменьшают никаких значений, если защитные элементы шаблона не совпадают. Мне бы хотелось, чтобы reduce
упрощал подвыражения Add
и др.