3
votes

Well, I've defined my own datatype that represent one-variable polynoms in Haskell.

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

I used here GADTs to constraint the a variable to belong to Num Class. Now I want to define my own instance for the Functor Class

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

And It does'nt compile giving me this reason:

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'

So I try to add this constraint to the fmap definition using language extension 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)

And It not works getting this from the compiler:

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'

Any idea how to fix that?

1
You can't constrain the types in the Functor class. There's an RFunctor class in the rmonad package that allows constraining the types, but you can't make Polinomio a Functor.Daniel Fischer
In general you should use type class constraints on functions rather than data types.Ankur
And how should it be done like in this case where I want to not allow to create polynoms with types that doesn't support (+) or (-) (Num Class) for instance?ctc
You should allow to create any type of polynoms as that is just data. But when you will provide functions that will process this data, those functions will say that they only work with Num class polynoms.Ankur

1 Answers

4
votes

You data type is

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

Now looking at your definition of Functor

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

The ghc is able to infer the constraints Num a for x due to GADT constraints. But the problem is in unrestricted function f as f :: a -> b, x :: Num a => a infers f x to be of type b. So it is not able to restrict f x to Num b => b which is required by Cons.

So as pointed by Daniel, You can not add constraints to your Functor class. Either you can define your own restricted Functor class like here or use RFunctor from rmonad.