[英]Num type class operations in Haskell?
我正在尝试用Haskell写一个口译员(确切地说,我正在看《 48小时内将自己写成一个方案》)。 我尝试将浮点运算添加到解释器。 现在,我有以下代码:
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类型类中存在的操作,该怎么办? 如何进行上述代码类型检查?
问题是您正在尝试将类型a -> a -> a
op
a -> a -> a
的函数op
应用于特定类型。 您的签名说的是“ op
是特定类型a
上的二进制运算符”。 也就是说, a
由传入的函数确定,它可能不是Integer
或Float
。 (GHC在第二个定义中给出警告,这有点奇怪,但是如果您注释掉后三个定义,则仅doNumeric
为两个Number
定义doNumeric
时也会看到它。)
使用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
type a
,我怀疑这是您要的。 因此,您可以使用(+)
来调用doNumeric
,但是不能使用f :: Int -> Int -> Int
doNumeric
f :: Int -> Int -> Int
来调用doNumeric
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.