Haskell: Operations on Double and Int give error “couldn't match expected type”-Collection of common programming errors
I’m writing a interpreter for my own language and I have an abstract syntax tree which has this type:
data Expression =
PInt Int
| PFloat Double
| PString String
| PChar Char
| PBool Bool
| Var String
| Unbound String String
| Unary String Expression
| Binary String Expression Expression
| Call Expression [Expression]
| Lambda Expression
| Assign String Expression Expression
| Conditional Expression Expression Expression
deriving Eq
I’m trying to write an instance of Num for my class so that I can use existing machinery for numerical operations. Here’s what I’ve written:
instance Num Expression where
PInt a + PInt b = PInt $ a + b
PInt a + PFloat b = PFloat $ a + b
PFloat a + PInt b = PFloat $ a + b
PFloat a + PFloat b = PFloat $ a + b
_ + _ = undefined
PInt a - PInt b = PInt $ a - b
PInt a - PFloat b = PFloat $ a - b
PFloat a - PInt b = PFloat $ a - b
PFloat a - PFloat b = PFloat $ a - b
_ - _ = undefined
PInt a * PInt b = PInt $ a * b
PInt a * PFloat b = PFloat $ a * b
PFloat a * PInt b = PFloat $ a * b
PFloat a * PFloat b = PFloat $ a * b
_ * _ = undefined
negate (PInt a) = PInt (-a)
negate (PFloat a) = PFloat (-a)
negate _ = undefined
abs (PInt a) = PInt $ abs a
abs (PFloat a) = PFloat $ abs a
abs _ = undefined
signum (PInt a) = PInt $ signum a
signum (PFloat a) = PFloat $ signum a
signum _ = undefined
fromInteger i = (PInt $ fromInteger i)
This gives me errors specifically in the places where I’ve combined ints and floats.
Prelude> :load AST.hs
[1 of 1] Compiling AST ( AST.hs, interpreted )
AST.hs:38:36:
Couldn't match expected type `Double' with actual type `Int'
In the first argument of `(+)', namely `a'
In the first argument of `PFloat', namely `(a + b)'
In the expression: PFloat (a + b)
AST.hs:39:37:
Couldn't match expected type `Double' with actual type `Int'
In the second argument of `(+)', namely `b'
In the second argument of `($)', namely `a + b'
In the expression: PFloat $ a + b
AST.hs:43:33:
Couldn't match expected type `Double' with actual type `Int'
In the first argument of `(-)', namely `a'
In the second argument of `($)', namely `a - b'
In the expression: PFloat $ a - b
AST.hs:44:37:
Couldn't match expected type `Double' with actual type `Int'
In the second argument of `(-)', namely `b'
In the second argument of `($)', namely `a - b'
In the expression: PFloat $ a - b
AST.hs:48:33:
Couldn't match expected type `Double' with actual type `Int'
In the first argument of `(*)', namely `a'
In the second argument of `($)', namely `a * b'
In the expression: PFloat $ a * b
AST.hs:49:37:
Couldn't match expected type `Double' with actual type `Int'
In the second argument of `(*)', namely `b'
In the second argument of `($)', namely `a * b'
In the expression: PFloat $ a * b
Failed, modules loaded: none.
This doesn’t make sense to me, since the type of an Int + Double in Haskell is a Double, so a + b should resolve to a Double, and since the constructor for a PFloat takes a Double, no problem… why is this not the case?
Resolved: using fromIntegral
in front of the variables of type Int
fixes it.
-
The mathematical operators in the Num typeclass expect both of their arguments to have the same type, so you’ll have to convert the Int to a Double using
fromIntegral
before you can add them together.For example, replace this
PInt a + PFloat b = PFloat $ a + b
with this
PInt a + PFloat b = PFloat $ fromIntegral a + b
Originally posted 2013-11-09 21:02:54.