2013-06-22 41 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。