Таким образом, существует много преимуществ наличия типов в форме C a Bool. В основном потому, что они позволяют вам выполнять любую логическую операцию между двумя ограничениями, когда обычный C a просто неявно И все.
Если мы рассмотрим ~ ограничение класса, это можно сделать так:
class Equal x y b | x y -> b
instance Equal x x True
instance False ~ b => Equal x y b
Но особый особенностью этого случая является то, что размещение x x в голове экземпляра эквивалентно x ~ y =>, а затем x y в голове. Это не относится к любому другому классу.
Поэтому, если мы попытаемся сделать что-то подобное для класса C, получим что-то вроде
class C' x b | x -> b
instance C x => C' x True
instance False ~ Bool => C' x b
К сожалению, это не работает, потому что только один из этих экземпляров когда-либо будет выбран, потому что они не различают тип x, поэтому любой тип соответствует обеим головам.
Я также прочитал https://www.haskell.org/haskellwiki/GHC/AdvancedOverlap, который снова не применяется для любого класса C, потому что он требует переписать все экземпляры исходного класса, В идеале я бы хотел, чтобы мой код работал с GHC.Exts.Constraint и KindSignatures, так что C может быть параметрическим.
Итак, для класса, подобного этому
class Match (c :: * -> Constraint) x b | c x -> b
Как написать экземпляры, чтобы Match c x True тогда и только тогда, когда c x, Match c x False в противном случае?