Что ж, простой ответ - отбросить арность из умного конструктора.
makePred :: Name -> Arguments -> Predicate
makePred name args = Pred name (length args) args
Тогда, если вы не выставите конструктор Pred
из вашего модуля и не заставите своих клиентов проходить через makePred
, вы знаете, что они всегда будут совпадать, и вам не нужен этот неприглядный Maybe
.
Не существует прямого способа применения этого инварианта.То есть вы не сможете получить makePred 2 ["a","b"]
для проверки типов, но makePred 2 ["a","b","c"]
- нет.Для этого вам нужны реальные зависимые типы.
В середине есть места, чтобы убедить haskell в принудительном применении ваших инвариантов с использованием расширенных возможностей (GADT
s + фантомных типов), но после написания целого решения я понялЯ на самом деле не отвечал на ваш вопрос, и что такие методы не совсем применимы к этой проблеме, в частности.Как правило, они доставляют больше хлопот, чем стоят вообще.Я бы придерживался умного конструктора.
Я написал подробное описание идеи умного конструктора .Оказывается, это довольно приятная середина между проверкой типа и проверкой во время выполнения.