2013-06-22 18 views
2

那么,我已经定义了我自己的数据类型,它代表了Haskell中的一变量多项式。GADTs和Functor类的问题

data Polinomio a where 
    Pol :: (Num a) => a -> Integer -> Polinomio a -> Polinomio a 
    Cons :: (Num a) => a -> Polinomio a 

我在这里使用GADT来约束一个变量属于Num类。 现在我想定义自己的实例为仿函数类

instance Functor Polinomio where 
    fmap f (Cons x) = Cons $ f x 
    fmap f (Pol x g p) = Pol (f x) g (fmap f p) 

,它一点儿也不编译给我这样的理由:

Polinomio_GADT.hs:31:23: 
Could not deduce (Num b) arising from a use of `Cons' 
from the context (Num a) 
    bound by a pattern with constructor 
      Cons :: forall a. Num a => a -> Polinomio a, 
      in an equation for `fmap' 
    at Polinomio_GADT.hs:31:13-18 
Possible fix: 
    add (Num b) to the context of 
    the data constructor `Cons' 
    or the type signature for 
     fmap :: (a -> b) -> Polinomio a -> Polinomio b 
In the expression: Cons 
In the expression: Cons $ f x 
In an equation for `fmap': fmap f (Cons x) = Cons $ f x 

Polinomio_GADT.hs:32:26: 
Could not deduce (Num b) arising from a use of `Pol' 
from the context (Num a) 
    bound by a pattern with constructor 
      Pol :: forall a. 
        Num a => 
        a -> Integer -> Polinomio a -> Polinomio a, 
      in an equation for `fmap' 
    at Polinomio_GADT.hs:32:13-21 
Possible fix: 
    add (Num b) to the context of 
    the data constructor `Pol' 
    or the type signature for 
     fmap :: (a -> b) -> Polinomio a -> Polinomio b 
In the expression: Pol (f x) g (fmap f p) 
In an equation for `fmap': 
    fmap f (Pol x g p) = Pol (f x) g (fmap f p) 
In the instance declaration for `Functor Polinomio' 

所以我尝试使用此约束添加到FMAP定义语言扩展InstanceSigs:

instance Functor Polinomio where 
    fmap :: (Num a,Num b) -> (a -> b) -> Polinomio a -> Polinomio b 
    fmap f (Cons x) = Cons $ f x 
    fmap f (Pol x g p) = Pol (f x) g (fmap f p) 

,它不是从作品的编译器得到这样的:

Polinomio_GADT.hs:31:13: 
Predicate `(Num a, Num b)' used as a type 
In the type signature for `fmap': 
    fmap :: (Num a, Num b) -> (a -> b) -> Polinomio a -> Polinomio b 
In the instance declaration for `Functor Polinomio' 

任何想法如何解决这个问题?

+0

您无法限制'Functor'类中的类型。 'rmonad'包中有一个'RFunctor'类,它允许限制类型,但是不能将'Polinomio'变成'Functor'。 –

+1

一般而言,您应该对函数而不是数据类型使用类型约束。 – Ankur

+0

在这种情况下,我应该如何处理?例如,如果我不想创建具有不支持(+)或( - )(Num Class)的类型的多项式, – ctc

回答

3

你的数据类型是

data Polinomio a where 
    Pol :: (Num a) => a -> Integer -> Polinomio a -> Polinomio a 
    Cons :: (Num a) => a -> Polinomio a 

现在在您的函子

instance Functor Polinomio where 
    fmap f (Cons x) = Cons $ f x 
    fmap f (Pol x g p) = Pol (f x) g (fmap f p) 

的定义看的GHC能够推断x约束Num a由于GADT约束。但是 问题处于无限制函数f中,因为f :: a -> b, x :: Num a => a推断f x的类型为b。所以无法将f x限制为Num b => b,这是Cons所要求的。

正如丹尼尔指出的那样,您不能为您的Functor 类添加约束条件。要么你可以定义你自己的受限制的Functor类,如here或使用从rmonad的RFunctor。