pmichaels
pmichaels

Reputation: 139

Haskell: polymorphic function is throwing type errors

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’

Failed, modules loaded: none.

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

Answers (1)

Fyodor Soikin
Fyodor Soikin

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

Related Questions