Haskell中的Num类操作?

时间:2014-03-04 03:44:53

标签: haskell typeclass

我正在尝试在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类型类中的操作,我该怎么办?如何进行上述代码检查?

1 个答案:

答案 0 :(得分:4)

问题是您尝试将类型为op的函数a -> a -> a应用于特定的类型。您的签名是“op特定类型a上的二元运算符”。也就是说,a由传入的函数决定,可能不是IntegerFloat。 (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