我正在尝试在Haskell写一个翻译(确切地说,我正在关注48小时内写自己的方案)。我尝试将float算法添加到解释器。现在我有以下代码:
data LispVal = Number Integer
| Float Float
deriving(Show, Eq)
doNumeric :: (Num a) => (a -> a -> a) -> LispVal -> LispVal -> LispVal
doNumeric op (Number a) (Number b) = Number $ a `op` b
doNumeric op (Float a) (Number b) = Float $ a `op` (fromIntegral b)
doNumeric op (Number a) (Float b) = Float $ (fromIntegral a) `op` b
doNumeric op (Float a) (Float b) = Float $ a `op` b
通过这种方式,我希望简单地通过以下方式构造加法,减法,乘法和除法等数值运算:doNumeric(+),doNumeric( - )..等等,这样我就不需要为doMul编写代码了,doAdd等。
但就上述代码而言,GHC抱怨说:
Couldn't match type `Integer' with `Float'
Expected type: a
Actual type: Float
In the first argument of `op', namely `a'
In the second argument of `($)', namely `a `op` (fromIntegral b)'
In the expression: Float $ a `op` (fromIntegral b)
因此,如果我希望op采用Num类型类中的操作,我该怎么办?如何进行上述代码检查?
答案 0 :(得分:4)
问题是您尝试将类型为op
的函数a -> a -> a
应用于特定的类型。您的签名是“op
是特定类型a
上的二元运算符”。也就是说,a
由传入的函数决定,可能不是Integer
或Float
。 (GHC在第二个定义上给出了警告,这有点奇怪,但是如果你注释掉最后三个,那么当你只为两个doNumeric
定义Number
时,你会看到它也会给出它。 。)
您使用op
的方式,您确实需要等级2类型:
{-# LANGUAGE RankNTypes #-}
doNumeric :: (forall a . (Num a) => a -> a -> a) -> LispVal -> LispVal -> LispVal
doNumeric op (Number a) (Number b) = Number $ a `op` b
...
这意味着op
保证适用于任何 Num
类型a
,我怀疑这是你想要的。因此,您可以使用doNumeric
拨打(+)
,但不能使用f :: Int -> Int -> Int
。