John F. Miller
John F. Miller

Reputation: 27217

Loss of polymorphism after pattern matching

The following code is intended to produce either a Double or an Integer. s is assumed to be either negate or id; n the whole part; and f the fractional part or Nothing for an integer.

computeValue :: Num a => (a->a) -> Integer -> (Maybe Double) -> Either Double Integer
computeValue s n Nothing = Right $ s n
computeValue s n (Just a) = Left $ s (fromIntegral n + a)

when I compile this I get:

test1.hs:2:28:
    Couldn't match type `Integer' with `Double'
    Expected type: Either Double Integer
      Actual type: Either Double a
    In the expression: Right $ s n
    In an equation for `computeValue':
        computeValue s n Nothing = Right $ s n

test1.hs:2:38:
    Couldn't match type `Integer' with `Double'
    In the first argument of `s', namely `n'
    In the second argument of `($)', namely `s n'
    In the expression: Right $ s n

It seems like somehow the compiler has lost track of the fact that s is polymorphic. What happened here and how do I fix it?

Upvotes: 7

Views: 365

Answers (1)

leftaroundabout
leftaroundabout

Reputation: 120711

s is not polymorphic from inside of your function: you can use any function that works on some Num instance as this parameter, it might be a function that only works on Complex! What you need is an universally quantified function s, i.e. one that can actually be called with any Num instance.

{-# LANGUAGE Rank2Types #-}

computeValue :: (forall a . Num a => a->a) -> Integer -> Maybe Double -> Either Double Integer
computeValue s n Nothing = Right $ s n
computeValue s n (Just a) = Left $ s (fromIntegral n + a)

That works then:

Prelude Data.Either> computeValue id 3 Nothing
Right 3
Prelude Data.Either> computeValue negate 57 (Just pi)
Left (-60.1415926535898)

Upvotes: 10

Related Questions