2012-03-03 88 views
6

我试图以归纳方式定义一对类实例。即:Haskell“不”类型约束

class Foo a b | a -> b where 
    foo :: a -> b 

instance (not?)Foo a => Bar a b 
    foo x = ... 

instance Foo a => Bar a b 
    foo x = ... 

第一个实例确定基本动作,秒递归调用foo。有没有办法做到这一点?一个很好的例子是扁平化一个列表,第一个例子是身份函数,第二个例子是concat的递归应用程序。

+10

请注意,在Haskell中,不可能确定给定类型是* not *给定类型类的实例,因为其他人可以使用他们自己的代码编译您的代码来提供实例。 – 2012-03-04 01:41:17

回答

5

这是一个implementation of a flatten function,适用于任何级别的嵌套列表。我不会真的推荐使用它 - 这里只是为了演示如何在Haskell中实现类似的功能。

+5

使用IncoherentInstances是一个麻烦的邀请。 – augustss 2012-03-04 02:08:18

+1

@augustss,非常真实,因此我放在榜首。不过,我认为没有'IncoherentInstances'就可以实现'flatten'(这可能是一个很好的表明,设计一个依赖这个函数的程序是一个坏主意)。 – 2012-03-04 05:02:02

+1

@ is7s:那里的解决方案不能派生出扁平列表的类型(所以你必须指定它为'flatten [[3],[4]] :: [Int]'。对于这个工作,你需要但是这可能是一个值得权衡的方法 – 2012-03-04 06:34:25

8

由于一个非常简单的原因,没有办法直接进行此操作 - 实例选择仅查看“头”,即=>之后的部分。在上下文中没有任何内容--之前的部分 - 可以影响选择哪个实例。

对于简单情况,您通常可以完全避免此问题,例如,如果数量有限的“基本情况”类型。一个常见的例子就是类型级别列表,其中有Cons的递归情况和Nil的基本情况,就是这样。

在一般情况下,您通常需要某种“条件测试”类型的类,根据是否满足某些条件来选择类型,然后将实际实现切换到一个“帮助器”类,条件结果值作为参数并用它来选择一个实例。

+1

那你如何实现一个通用列表展平类成员呢? – Jonathan 2012-03-03 23:59:51

+7

那么,最诚实的答案是,我不会。在我看来,如果没有打破多态输入,没有办法做到这一点,并没有足够的证明这个麻烦。这就是说,为了扁平化列表,我认为你可以依靠重叠的实例来选择递归还是基本的情况。你在这里使用'OverlappingInstances'吗?你可能会需要这种或那种方式。 – 2012-03-04 00:02:11

+3

为什么你想要一个通用列表展平功能?这很少有用。 – augustss 2012-03-04 02:09:53