Reputation: 139
I have the following case. As can be seen, I have a less than class that takes ints and returns a bool. I am trying to create a Polyeq class that can take either ints or bools (or maybe even strings) and evaluates to see if they are equal and return a bool:
class Symantics repr where
int :: Int -> repr Int
add :: repr Int -> repr Int -> repr Int
bool :: Bool -> repr Bool
newtype R a = R{unR :: a}
instance Symantics R where
int x = R x
add e1 e2 = R $ unR e1 + unR e2
bool b = R b
class Lth repr where
lth :: repr Int -> repr Int -> repr Bool
instance Lth R where
lth e1 e2 = R $ unR e1 < unR e2
class Polyeq a where
polyeq :: a -> a -> Bool
instance Polyeq R where
polyeq e1 e2 = R $ unR e1 == unR e2
I get the following error when compiling:
error:
• Couldn't match expected type ‘Bool’ with actual type ‘R Bool’
• In the expression: R $ unR e1 == unR e2
In an equation for ‘polyeq’: polyeq e1 e2 = R $ unR e1 == unR e2
In the instance declaration for ‘Polyeq Int’
error:
• Couldn't match expected type ‘R a0’ with actual type ‘Int’
• In the first argument of ‘unR’, namely ‘e1’
In the first argument of ‘(==)’, namely ‘unR e1’
In the second argument of ‘($)’, namely ‘unR e1 == unR e2’
error:
• Couldn't match expected type ‘R a0’ with actual type ‘Int’
• In the first argument of ‘unR’, namely ‘e2’
In the second argument of ‘(==)’, namely ‘unR e2’
In the second argument of ‘($)’, namely ‘unR e1 == unR e2’
updated code: now throwing
error:
• Expecting one more argument to ‘R’
Expected a type, but ‘R’ has kind ‘* -> *’
• In the first argument of ‘Polyeq’, namely ‘R’
In the instance declaration for ‘Polyeq R’
Failed, modules loaded: none.
Upvotes: 0
Views: 75
Reputation: 80805
Your implementation of Polyeq R
has two problems: first, its parameter R
has the wrong kind (the class specifies *
, but R
has kind * -> *
), and second the implementation of method polyeq
returns R
while its signature calls for Bool
The shortest way to fix is to provide the expected kind and expected implementation:
instance Polyeq (R a) where
polyeq e1 e2 = unR e1 == unR e2
But I suspect what you really meant was for the class to be defined on a variable of kind * -> *
, similar to the Symantics
class and its method add
:
class Polyeq repr where
polyeq :: Eq a => repr a -> repr a -> repr Bool
instance Polyeq R where
polyeq e1 e2 = R $ unR e1 == unR e2
I must also note that customarily these things are achieved via an Applicative
instance and liftA2
.
If you define an Applicative
instance for R
:
instance Functor R where
fmap f (R x) = R $ f x
instance Applicative R where
pure = R
liftA2 f (R a) (R b) = R $ f a b
Then all definitions in your classes degrade into:
int = pure
bool = pure
add = liftA2 (+)
lth = liftA2 (<)
polyeq = liftA2 (==)
Upvotes: 4