Haskell - соответствие шаблону GADTs с ограничениями класса

Рассмотрим следующий пример

# LANGUAGE DataKinds, GADTs #
data Phantom = A | B
data Foo (a :: Phantom) where
  FooA :: Foo 'A
  FooB :: Foo 'B
class PhantomConstraint (a :: Phantom)
instance PhantomConstraint 'A -- Note: No instance for 'B
someFunc :: PhantomConstraint a => Foo a -> ()
someFunc FooA = ()

Если я сделаю что-то вроде этого, GHC жалуется, что совпадения шаблонов не являются исчерпывающими для someFunc , однако, если я попытаюсь включить случай FooB (который я не хочу делать для конкретных доменных причин), он жалуется, что он не может вывести экземпляр PhantomConstraint для Foo 'B

Можно ли каким-либо образом сопоставить соответствие шаблону GADT с ограничениями типа текста, чтобы исключить требуемые комбинации соответствия шаблону?

EDIT: более подробно о том, что я хочу сделать. У меня есть ведро типов, которые все связаны друг с другом, но имеют разные свойства. В мире OO это то, что люди используют подтипирование и наследование. Однако в сообществе FP консенсус, похоже, заключается в том, что нет реального хорошего способа делать подтипирование, поэтому в этом случае мне нужно взломать его. Таким образом, у меня есть GADT, который объединяет все типы, но с разными параметрами этого типа. Затем я перехожу к написанию разных типов и экземпляров typeclass в параметрах типа (включенными datakinds, без представления термина). Я хочу быть в состоянии выразить, что некоторые из этих типов из datakinds обладают свойством, которого нет у других, но все они имеют общие общие свойства, поэтому я действительно не хочу разбивать тип. Единственный другой вариант, который я могу предвидеть, - создать таксономию в части типа, но тогда типы DataKinds будут испорчены.

Всего 1 ответ


Я не могу воспроизвести эту проблему. Это загружает без предупреждений или ошибок в GHCi 8.4.3.

# LANGUAGE GADTs, DataKinds, KindSignatures #
# OPTIONS -Wall #
module GADTwarning2 where

data Phantom = A | B

data Foo (a :: Phantom) where
  FooA :: Foo 'A
  FooB :: Foo 'B

class PhantomConstraint (a :: Phantom)

instance PhantomConstraint 'A -- Note: No instance for 'B

someFunc :: PhantomConstraint a => Foo a -> ()
someFunc FooA = ()
someFunc FooB = ()

Как пояснил luqui в комментарии, мы не можем избежать случая FooB , так как классы классов открыты, а другой экземпляр может быть добавлен позже другим модулем, что делает шаблон не исчерпывающим.

Если вы абсолютно уверены, что вам не нужны никакие другие экземпляры, кроме одного для A , вы можете попытаться использовать

class a ~ 'A => PhantomConstraint (a :: Phantom)

Или, если индекс a может быть 'A или 'B , но никогда не является третьим конструктором 'C , мы можем попытаться подтвердить этот факт:

class PhantomConstraint (a :: Phantom) where
   aIsAOrB :: Either (a :~: 'A) (a :~: 'B)

а затем использовать этот член позже.


Есть идеи?

10000