2015-03-03 49 views
2

我有一个功能foo与一系列的约束。当然,这些约束必须出现在使用foo的函数的签名中,所以我试图做的是将foo约束包含在类型同义词FooCtx a b ... :: Constraint中。作为一个例子,利用fundeps绑定约束

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上不能有任何隐藏类型。有没有其他方法可以完全收集所有这些限制?

+0

“type FooCtx a b = ...'出现了什么问题 - 这只比'type FooCtx a = ...'长2个字符。 – user2407038 2015-03-03 04:16:56

+0

正如我上面提到的,GHC接受你的签名,但对于'foo'的LHS我没用,因为'b'不在'foo'的签名范围内。 – crockeea 2015-03-03 04:18:58

+0

是否有任何理由不能使用'TypeFamilies'而不是'FunctionalDependencies'? – Cirdec 2015-03-03 04:59:14

回答

5

你误解了类型变量是如何绑定的。它们是而不是,由tau类型(在本例中为a -> a)绑定,但是基于完整phi类型的隐式绑定器((Bar a b) => a -> a)。使用GHC语言扩展可以明确该绑定。

在您的例子,当你喜欢写东西

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

然后充分σ型,具有明确tyvar结合拼出来的,是下面的(因为在隐式情况下,从披类型的所有tyvars这里必然)

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 
+0

有趣!谢谢。 – crockeea 2015-03-03 05:23:02

1

这个问题可以通过TypeFamiliesFlexibleContexts来解决。

{-# LANGUAGE TypeFamilies #-} 
{-# LANGUAGE FlexibleContexts #-} 

我们有三个班,ABC和你原来的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)