2012-06-12 136 views
3

我开始用GHC 7.4.2中的新类约束扩展来弄湿我的脚,但是我有一些问题需要一个小例子来工作。代码如下:haskell约束系列

{-# LANGUAGE UndecidableInstances, 
     MultiParamTypeClasses, 
     KindSignatures, 
     TypeFamilies, 
     Rank2Types, 
     ConstraintKinds, 
     FlexibleInstances, 
     OverlappingInstances #-} 

module Test where 

    import GHC.Exts -- to get Constraint type constructor 

    class NextClass f where 
    type Ctxt f a :: Constraint 
    next :: (Ctxt f a) => a -> a 

    instance NextClass Int where 
    type Ctxt Int a = Num a 
    next b = b + 1 

    n :: (NextClass a) => a -> a 
    n v = next v 

我想要做的就是定义一个NextClass类型的类,这将让我(给定值x)得到X的下一个值是的情况下,所有类型是什么NextClass。要使用+运算符,我需要Num a类约束Int

然而,GHC给了我以下错误:

Could not deduce (Ctxt f0 a) arising from a use of `next' 
from the context (NextClass a) 
    bound by the type signature for n :: NextClass a => a -> a 
In the expression: next v 
In an equation for `n': n v = next v 

我怀疑GHC告诉我,它没有足够的信息来确定要使用的约束族实例。

有人可以解释我在做什么错在这里。这是限制家庭的正确使用吗?

TIA

回答

5

你的定义中有一些奇怪的事情发生。首先,(只)类方法next的类型从未提及类变量f。编译器应该如何选择使用哪个类型的实例?我要去承担你的意思是这样的:

{-# LANGUAGE ConstraintKinds, TypeFamilies #-} 
module Test where 

import GHC.Exts -- to get Constraint type constructor 

class NextClass f where 
    type Ctxt f :: Constraint 
    next :: Ctxt f => f -> f 

instance NextClass Int where 
    type Ctxt Int = Num Int 
    next b = b + 1 

n :: (NextClass a) => a -> a 
n v = next v 

接下来的奇异之处在于Int已经有一个Num实例,所以这是没有太大的约束。但是,让我们离开那个放在一边(因为它不会影响我们得到的错误),只是看看新的错误:

test.hs:15:7: 
    Could not deduce (Ctxt a) arising from a use of `next' 
    from the context (NextClass a) 
     bound by the type signature for n :: NextClass a => a -> a 
     at test.hs:15:1-12 
    In the expression: next v 
    In an equation for `n': n v = next v 

其实,这个错误是非常明智的:约束的整点是,有一个NextClass a的实例是不够的;我们还必须有一个Ctxt a的实例。所以我们可以修复类型签名:

n :: (NextClass a, Ctxt a) => a -> a 
n v = next v 

...然后它编译。最后的奇异之处在于这是一个特别退化使用约束类型的,因为这简单的代码基本上是等价的:

class NextClass f where 
    next :: f -> f 

instance Num Int => NextClass Int where 
    next b = b + 1 

...并从以前的事了新的东西翻译是很机械的:不是声明instance NextClass {- foo -} where type Ctxt {- foo -} = {- bar -},您只需写入instance {- bar -} => NextClass {- foo -}

+0

感谢丹尼尔,我改变了我的代码使用'实例Num Int => NextClass Int其中...'。这是在Haskell中编写这种类型代码的惯用方法吗? –

+0

@RananvanDalen那么,惯用的方法是'实例NextClass Int其中...'没有无约束的约束或'newtype SuccNext a = SuccNext a;实例Num a => NextClass(SuccNext a)其中...具有多态类型(以及防止虚假重叠的新类型)。 –

+0

好东西。我必须再读一遍类型类:) –