Reputation: 1
Hello i need to create a class which contains a method called prize'
which calculates some Fractional. I want to instance in case I get an Order
, later I will have to instance again in case I get a [Order]
, this is the code :
class Ped a where
prize' :: Fractional b => a -> b
instance (Integral n, Fractional p) => Ped (Order n p) where
prize' x = prizeOrder x
data (Integral c,Fractional p) => Product c p
= Prod c String p
deriving (Show, Read)
data (Integral n, Fractional p) => Order n p
= PdMult (Product n p) n
| PdUnit (Product n p)
deriving (Show, Eq)
prize :: (Fractional p, Integral c) =>(Product c p) -> p
prize (Prod _ _ x) = x
prizeOrder :: (Fractional p, Integral c) => (Order c p) -> p
prizeOrder (PdMult p n) = (prize p) * (fromIntegral n)
prizeOrder (PdUnit p) = prize p
Prelude says:
Could not deduce (p ~ b)
from the context (Integral n, Fractional p)
bound by the instance declaration
at src\Funciones.hs:6:10-55
or from (Fractional b)
bound by the type signature for
prize' :: Fractional b => Order n p -> b
at src\Funciones.hs:7:5-11
`p' is a rigid type variable bound by
the instance declaration
at src\Funciones.hs:6:10
`b' is a rigid type variable bound by
the type signature for prize' :: Fractional b => Order n p -> b
at src\Funciones.hs:7:5
Expected type: Order b
Actual type: Order n p
Relevant bindings include
x :: Order n p
(bound at src\Funciones.hs:7:13)
prize' :: Order n p -> b
(bound at src\Funciones.hs:7:5)
In the first argument of `prizeOrder', namely `x'
In the expression: prizeOrder x
Upvotes: 0
Views: 137
Reputation: 476584
The problem is that your class
definition gives an additional degree of freedom, your instance
fails to provide. In your class you state:
class Ped a where
prize' :: Fractional b => a -> b
That means that the programmer could choose whatever Fraction b
for b
he/she wants.
Now if we look to your instance:
instance (Integral n, Fractional p) => Ped (Order n p) where
prize' x = prizeOrder x
Here you say that prize'
depends on prizeOrder
. The prizeOrder
function has however the signature:
prizeOrder :: (Fractional p, Integral c) => (Order c p) -> p
Which means you cannot choose b
at all. If I would use prize'
with as expected return type Float
, that would be accepted by Ped
, but not by a datastructure Order Double Int
.
You can "solve" this by using multi-parameter classes, you take the b
in the class
signature:
class Ped a b where
prize' :: a -> b
Next you need to define the instance with a second type parameter to ensure the output is p
:
instance (Integral n, Fractional p) => Ped (Order n p) p where
prize' x = prizeOrder x
You will need to activate some additional GHC features, the full code would read like:
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE DatatypeContexts #-}
class Ped a b where
prize' :: a -> b
instance (Integral n, Fractional p) => Ped (Order n p) p where
prize' x = prizeOrder x
data (Integral c,Fractional p) => Product c p
= Prod c String p
deriving (Show, Read)
data (Integral n, Fractional p) => Order n p
= PdMult (Product n p) n
| PdUnit (Product n p)
deriving (Show)
prize :: (Fractional p, Integral c) =>(Product c p) -> p
prize (Prod _ _ x) = x
prizeOrder :: (Fractional p, Integral c) => (Order c p) -> p
prizeOrder (PdMult p n) = (prize p) * (fromIntegral n)
prizeOrder (PdUnit p) = prize p
But as said by @bheklilr, don't use "class constraints on data types". Furthermore one better asks his/herself whether it pays off to use a class
.
Upvotes: 1