This is called higher rank types, basically the type you want is
binop :: (forall a. Num a => a -> a -> a) -> [Value] -> EvalM Value
But what you have is
binop :: forall a. Num a => (a -> a -> a) -> [Value] -> EvalM Value
Do you see the difference? With the first function, the operator is actually polymorphic within the function, it says "Given a function that takes any Num a
of type a -> a -> a
...". The second one says, "For all a
, given a function from a single arbitrary a -> a -> a
...".
Luckily GHC supports higher rank types,
{-# LANGUAGE RankNTypes #-}
...
binop :: (forall a. Num a => a -> a -> a) -> [Value] -> EvalM Value
binop (+) [VFloat a, VFloat b] = return $ VFloat (a + b)
binop (+) [VInt a, VFloat b] = return $ VFloat (fromInteger a + b)
binop (+) [VFloat a, VInt b] = return $ VFloat (a + fromInteger b)
binop (+) [VInt a, VInt b] = return $ VInt (a + b)
binop _ [_,_] = throwError "Currently only adding numbers"
binop _ _ = throwError "Arity Error: Add takes 2 arguments"
However the type inferencer doesn't do so hot with higher rank types, so you will likely have to add explicit signatures.