3

我开始对 GHC 7.4.2 中的新类约束扩展感到困惑,但我在让一个小例子工作时遇到了一些问题。代码如下:

{-# 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

4

1 回答 1

5

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

{-# 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

实际上,这个错误看起来很合理:约束的全部意义在于拥有一个 for 的实例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 -}

于 2012-06-12T07:20:09.283 回答