
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).