[Haskell-cafe] Typeclass question

Stefan O'Rear stefanor at cox.net
Sun Dec 3 12:37:02 EST 2006


On Sun, Dec 03, 2006 at 12:26:30PM -0500, Jonathan Tang wrote:
> I've got what's probably a beginner's question, but I'm out of ideas
> for solving it.  It looks like it tripped me up in "Write Yourself a
> Scheme..." too, since the code there seems like it's arranged so I
> never ran into it...
> 
> I've got a couple functions:
> 
> binop :: (AmbrosiaData -> AmbrosiaData -> AmbrosiaM AmbrosiaData) ->
> AmbrosiaM ()
> binop operator = do
>  second <- popStack
>  first <- popStack
>  result <- operator first second
>  pushStack result
> 
> numNumOp ::  Num a => (a -> a -> a) -> AmbrosiaData -> AmbrosiaData ->
> AmbrosiaM AmbrosiaData
> numNumOp op (Number val1) (Number val2) = return $ Number $ op val1 val2
> numNumOp op (Float val1) (Float val2) = return $ Float $ op val1 val2
> numNumOp op _ _ = throwError . TypeMismatch $ "Number"

When you say Num a => (a -> a -> a) -> ..., what that means is:

numNumOp :: forall a. Num a => ((a -> a -> a) -> AmbrosiaData -> AmbrosiaData -> AmbrosiaM AmbrosiaData)

That is, what you pass must be a single type.  It looks like what you
want is:

numNumOp :: (forall a. Num a => (a -> a -> a)) -> AmbrosiaData -> AmbrosiaData -> AmbrosiaM AmbrosiaData

Notice that forall is in the argument - thus numNumOp must recieve a
polymorphic argument.  This is called rank-2 polymorphism, and numNumOp
is a rank-2 polymorphic function. Unfortunately, it turns out that
allowing foralls inside function arguments makes typechecking much
harder, in general impossible.  GHC allows it but requires explicit type
annotations on all rank-2 polymorphic functions.  Haskell98 forbids
rank-2 polymorphism altogether (and explicit foralls, for that matter).


More information about the Haskell-Cafe mailing list