Таким образом, существует много преимуществ наличия типов в форме 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
в противном случае?