data Foo = Bar1
| Bar2 Foo Foo
| Bar3 Foo
| Bar4 Foo Foo Foo
Теперь предположим, что кто-то создал дерево Foo
, и я хочу проверить, действительны ли аргументы значения Foo. Правила о аргументах конструкторов являются:Как выразить соответствие шаблону для независимых комбинаций значений данных?
Bar2 Bar1 Foo
Bar3 (Bar2|Bar3|Bar4)
Bar4 Bar1 Bar1 (Bar1|Bar4)
Я знаю, конструктор значения и только хочу, чтобы проверить непосредственные аргументы, ничего рекурсивного. Пример:
bar2 Bar1 Bar1 = True
bar2 Bar1 (Bar2 {}) = True
bar2 Bar1 (Bar3 _) = True
bar2 Bar1 (Bar4 {}) = True
bar2 _ _ = False
И, например, аналогично для Bar4:
bar4 Bar1 Bar1 Bar1 = True
bar4 Bar1 Bar1 (Bar4 {}) = True
bar4 _ _ _ = False
Как я могу выразить эти условия наиболее кратко? Листинг всех комбинаций в некоторых случаях слишком много. И, насколько мне известно, «OR» -syntax для сопоставления шаблонов не существует.
UPDATE
Я приспособил решение Даниила и пришел к этому:
data Foo = Bar1
| Bar2 Foo Foo
| Bar3 Foo
| Bar4 Foo Foo Foo
deriving (Data, Typeable)
bar2 a b = a `isOf` [Bar1] && b `isOf` [Bar1,Bar2{},Bar3{},Bar4{}]
bar4 a b c = [a,b] `areOf` [Bar1] && c `isOf` [Bar1,Bar4{}]
isOf l r = toConstr l `elem` map toConstr r
areOf l r = all (`isOf` r) l
Что мне нравится в том, что я не должен изменить тип данных, за исключением добавления Выводя и что он доступен для чтения. Конечно, недостатком является то, что это динамические проверки. В моем случае это нормально, хотя, как правило, для проверок типа assert, чтобы обнаружить ошибки программирования.
Являются ли эти комбинации единственными законными видами использования 'Bar2',' Bar3' и 'Bar4'? (I.e - это условия, проверяющие, что они являются «законными»). Если это так, то, вероятно, лучше попытаться кодировать условия в системе типов, поэтому нет возможности их разбить. – huon
Да, я тоже думал о том, чтобы делать это с типами. Но мои попытки еще не были успешными. Я попробовал это с GADT. – letmaik
Просто заметьте, вы можете упростить шаблон для 'Bar2' как' bar2 Bar1 _ = True'. –