Как объединить два ограничения типа с логическим или в Haskell?
в Haskell нам предоставляется возможность комбинировать ограничения по типам с логическим И.
рассмотрим следующее
type And (a :: Constraint) b = (a, b)
или более изощренно -
class (a, b) => And a b
instance (a, b) => And a b
Я хочу знать, как логически или два ограничения вместе в Haskell.
моя ближайшая попытка-это, но она не совсем работает. В этой попытке я reify ограничения типа с тегами и чем dereify их с неявными параметрами.
data ROr a b where
L :: a => ROr a b
R :: b => ROr a b
type Or a b = (?choose :: ROr a b)
y :: Or (a ~ Integer) (Bool ~ Integer) => a
y = case ?choose of
L -> 4
x :: Integer
x = let ?choose = L in y
Это почти работает, но пользователь должен применить заключительную часть, и компилятор должен сделать это за меня. Кроме того, этот случай не позволяет выбрать третий выбор, когда оба ограничения удовлетворены.
как я могу логически или два ограничения вместе?
2 ответов
Я считаю, что нет никакого способа, чтобы автоматически выбрать ROr a b
; это нарушило бы предположение открытого мира, если, например,b
было удовлетворено, но позже a
также был удовлетворен; любое правило разрешения конфликтов обязательно приведет к добавлению экземпляра для изменения поведения существующего кода.
то есть, взяв R
, когда b
удовлетворен, но a
не нарушает предположение открытого мира, потому что оно включает в себя решение о том, что экземпляр не удовлетворены;1 даже если вы добавили конструктор" оба удовлетворены", вы сможете использовать его, чтобы решить, является ли экземпляр не present (увидев, если вы получите L
или R
).
поэтому я не верю, что такое или ограничение возможно, если вы можете наблюдать, какой экземпляр вам, то вы можете создать программу, поведение которой изменяется путем добавления экземпляра, и если вы не можете наблюдать пример вы получаете, то это довольно бесполезно.
1 разница между этим и обычным разрешением экземпляра, которое также может завершиться ошибкой, заключается в том, что обычно компилятор не может решить, что ограничение выполнено; здесь вы просите компилятор решить, что ограничение не может быть выполнено. Тонкое, но важное различие.
Я пришел сюда, чтобы ответить на ваш вопрос о кафе. Не уверен, что q здесь то же самое, но в любом случае ...
класс типа с тремя параметрами.
class Foo a b c | a b -> c where foo :: a -> b -> c instance Foo A R A where ... instance Foo R A A where ...
в дополнение к функциональной зависимости я хотел бы выразить, что по крайней мере один из параметров a и b-c,
import Data.Type.Equality
import Data.Type.Bool
class ( ((a == c) || (b == c)) ~ True)
=> Foo a b c | a b -> c where ...
вам понадобится куча расширений включено. В частности UndecidableSuperClasses
, потому что вызовы семейства типов в ограничении класса непрозрачны как GHC может видеть.
ваш q здесь
как я могу логически или два ограничения вместе?
гораздо сложнее. Для подхода равенства типов ==
использует семейство закрытого типа. Таким образом, вы можете написать семейство закрытого типа, возвращающее вид Constraint
, но я сомневаюсь, что есть общее решение. Для Foo
класс:
type family AorBeqC a b c :: Constraint where
AorBeqC a b a = ()
AorBeqC a b c = (b ~ c)
class AorBeqC a b c => Foo a b c | a b -> c where ...
вероятно, у него будет плохое и несимметричное поведение улучшения типа: если GHC может видеть это a, c
отдельно, он перейдет ко второму уравнению и использует (b ~ c)
чтобы улучшить либо; если он не видит, что они разделены или что они унифицированы, он застрянет.
в общем, как указывает @ehird, вы не можете проверить, является ли ограничение не satisfiable. Равенства типа особенный.