haskell - 与fundeps捆绑约束

标签 haskell ghc functional-dependencies type-constraints

我有一个函数foo并受到一连串的限制。当然,这些约束必须出现在使用foo的函数的签名中。 ,所以我想做的就是包装 foo类型同义词中的约束 FooCtx a b ... :: Constraint 。举个例子,

foo :: (A a, B b, C c, ...) => a -> b -> c

bar :: (A a, B b, C c, ...) ...
bar = ... foo ...

会变成

type FooCtx a b c ... = (A a, B b, C c, ...)
foo :: (FooCtx a b c) => a -> b -> c
bar :: (FooCtx a b c) => ...

如果所有类型都公开,这会非常有效。但是,我使用函数依赖关系来生成约束列表中的某些类型,并且这些类型不会出现在 foo 的签名中。例如:

class Bar a b | a -> b

foo (Bar a b, ...) => a -> a

GHC 不会接受 type FooCtx a = (Bar a b)因为b不受 LHS 约束。我也不能使用type FooCtx a b = (Bar a b)因为b不在 foo 签名的范围内。 foo的签名将是foo :: (FooCtx a ?) => a -> a .

一个不令人满意的解决方案是将约束之一放在 foo 中。签名为FooCtx将fundep类型纳入范围:

class Bar a b | a -> b

type FooCtx a b = ...

foo (Bar a b, FooCtx a b) => a -> a

但这违背了对约束进行分组的目的:

在遇到这种情况之前,我认为约束同义词可以盲目地替换任意约束列表。我知道封装这样的约束的唯一其他方法是使用类,但它遇到了同样的问题:class (A a, B b, C c, ...) => FooCtx a b c LHS 上不能有任何隐藏类型。有没有其他方法可以完全收集所有这些约束?

最佳答案

您误解了类型变量的绑定(bind)方式。它们受 tau 类型(示例中的 a -> a)绑定(bind),而是基于完整 phi 类型的隐式绑定(bind)器 ((Bar a b ) => a -> a)。可以使用 ExplicitForAll GHC 语言扩展来明确此绑定(bind)。

在您的示例中,当您编写类似的内容时

foo :: (Bar a b) => a -> a

然后,完整的 sigma 类型(具有明确的 tyvar 绑定(bind)拼写)如下(因为在隐式情况下,来自 phi 类型的所有 tyvar 都绑定(bind)在此处)

foo :: forall a b. (Bar a b) => a -> a

这意味着以相同的方式使用约束别名没有问题:如果您有例如

type FooCtx a b = (Bar a b, Num a, Eq a)

那么以下是有效的类型签名:

foo' :: forall a b. (FooCtx a b) => a -> a

因此,以下简写也是有效的:

foo' :: (FooCtx a b) => a -> a

关于haskell - 与fundeps捆绑约束,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28823727/

相关文章:

haskell - 如何避免类型类实例的二次爆炸?

Haskell 输入 Int 和 Double 类型

haskell - 在 Haskell 中搜索玫瑰树

haskell - 有没有办法在 GHC 编译时打开约束字典?

haskell - 为什么 Haskell case 语句中的默认包罗万象不是强制性的?

haskell - 什么时候unsafeInterleaveIO不安全?

macos - GHC 6.12 和 MacPorts

database - 简单的关系分解例子——信息不足?