在Haskell中,我们可以将类型的约束与逻辑和。
结合起来考虑以下
type And (a :: Constraint) b = (a, b)
或更复杂
class (a, b) => And a b
instance (a, b) => And a b
我想知道如何在Haskell中逻辑地或两个约束。
我最接近的尝试就是这个,但它并不常用。在这次尝试中,我用标签来表示类型约束,而不是用隐式参数去除它们。
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
它几乎可以工作,但用户必须应用最后一部分,编译器应该为我这样做。同样,当满足两个约束时,这种情况不会让人选择第三种选择。
我如何逻辑或两个约束在一起?
答案 0 :(得分:14)
我相信没有办法自动选择ROr a b
;如果,例如,它会违反开放世界的假设。 b
感到满意,但后来a
也感到满意;任何冲突解决规则都必然会导致添加一个实例来改变现有代码的行为。
也就是说,在满足R
时选择b
但a
并未打破开放世界的假设,因为它涉及决定实例而不是满意; 1 即使你添加了“两个满意的”构造函数,你也可以使用它来决定一个实例是否不存在(通过查看你是否得到一个L
或R
)。
因此,我不相信这样的或约束是可能的;如果你可以观察到你得到的实例,那么你可以通过添加一个实例创建一个行为改变的程序,如果你不能观察到你得到的实例,那么它就没用了。
1 此实例和正常实例解析之间的差异,也可能失败,通常是编译器无法确定是否满足约束;在这里,您要求编译器确定不能满足约束。一个微妙但重要的区别。
答案 1 :(得分:0)
我来这里是在咖啡馆回答您的问题。不确定这里的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指出的那样,您无法测试约束是否满足。类型相等是特殊的。