The problem is that you are trying to apply a function op
with type a -> a -> a
to a specific type. What your signature says is "op
is a binary operator on a specific type a
". That is, a
is determined by the function that is passed in, and it may not be Integer
or Float
. (It's a bit odd that GHC gives you the warning on the second definition, but if you comment out the last three, you'll see it also gives it when you just define doNumeric
for two Number
s.)
The way you are using op
, you really need a rank 2 type:
{-# LANGUAGE RankNTypes #-}
doNumeric :: (forall a . (Num a) => a -> a -> a) -> LispVal -> LispVal -> LispVal
doNumeric op (Number a) (Number b) = Number $ a `op` b
...
What this means is that op
is guaranteed to work for any Num
type a
, which I suspect is what you are going for. Hence you can call doNumeric
with (+)
, but not with f :: Int -> Int -> Int
.