Haskell 捆绑约束与fundeps

Haskell 捆绑约束与fundeps,haskell,ghc,functional-dependencies,type-constraints,Haskell,Ghc,Functional Dependencies,Type Constraints,我有一个函数foo,有一系列约束。当然,这些约束必须出现在使用foo的函数的签名中,因此我尝试将foo约束包装在类型同义词FooCtx a b…::约束。例如, 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

我有一个函数
foo
,有一系列约束。当然,这些约束必须出现在使用
foo
的函数的签名中,因此我尝试将
foo
约束包装在类型同义词
FooCtx a b…::约束
。例如,

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=(条形图a b)
,因为
b
未绑定在LHS上。我也不能使用
type FooCtx a b=(Bar a b)
,因为
b
不在
foo
的签名范围内。
foo
的签名将是
foo::(fooctxa?=>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(aa,bb,cc,…)=>fooctxabc
在LHS上不能有任何隐藏类型。是否有其他方法可以完全收集所有这些约束?

您误解了类型变量的绑定方式。它们不是受tau类型(示例中的
a->a
)约束的,而是基于完整phi类型的隐式绑定(
(Bar a b)=>a->a
)。此绑定可以通过GHC语言扩展名
ExplicitForAll
显式进行

在您的示例中,当您编写以下内容时

foo :: (Bar a b) => a -> a
然后,完整的sigma类型,以及显式的tyvar绑定,如下所示(因为在隐式情况下,来自phi类型的所有tyvar都在这里绑定)

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

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

这个问题可以通过
TypeFamilies
FlexibleContexts
解决

{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE FlexibleContexts #-}
我们有三个类,
A
B
C
以及您原来的
foo
函数

class A a
class B a
class C a

foo :: (A a, B b, C c) => a -> b -> c
foo = undefined
Bar
类使用类型族来计算
B
a
的搭配。我向它添加了一个附加函数,只是为了编写示例
foo'

class Bar a where
    type BofA a :: *
    aToB :: a -> BofA a
foo'
是一个函数,它没有任何
B
的输入或输出,但在其实现中仍然使用
foo
。它要求与
a
关联的
BofA
类型满足
B
约束。此签名需要灵活的上下文

foo' :: (A a, Bar a, B (BofA a), C c) => a -> a -> c
foo' x y = foo x (aToB y)

type FooCtx a b=…
有什么问题-这只比
type FooCtx a=…
长2个字符。如上所述,GHC接受您的签名,但是在
foo
的LHS上,它对我来说是无用的,因为
b
不在
foo
的签名范围内。你有什么理由不能用
TypeFamilies
代替
功能依赖性吗?@Cirdec既然你提到了它,有什么理由吗?它们不是同构的吗?这将允许我把这些新类型的范围…多么有趣!谢谢
foo' :: (A a, Bar a, B (BofA a), C c) => a -> a -> c
foo' x y = foo x (aToB y)