我对 Haskell 很陌生,所以我希望这不是一个愚蠢的问题。我有这个数据类型:
data N = I Int | D Double deriving (Show, Eq)
我正在尝试编写一个带有签名(Num a) => (a -> a -> a) -> N -> N -> N
的函数,该函数将该函数应用于N
s 中的数字并返回 N 和结果。如果N
s 都是D
s,它应该只应用函数并返回 a D
; 如果一个是 anI
另一个是 a D
,它应该将Int
in转换I
为 a Double
,将函数应用于两个Double
s,并返回 a D
;如果两者都是I
s,它应该应用该函数并返回一个I
. 这是我到目前为止的(损坏的)代码:
widen :: N -> N -> (N, N)
widen (I i) d@(D _) = (D (fromIntegral i), d)
widen d@(D _) i@(I _) = widen i d
widen x y = (x, y)
numOp :: (Num a) => (a -> a -> a) -> N -> N -> N
numOp op x y = case widen x y of (D x', D y') -> D $ x' `op` y'
(I x', I y') -> I $ x' `op` y'
不过,我在两行都收到错误numOp
。第一个是:
Could not deduce (a ~ Double)
from the context (Num a)
bound by the type signature for
numOp :: Num a => (a -> a -> a) -> N -> N -> N
at <line num>
In the second argument of `($)', namely x' `op` y'
In the expression: D $ x' `op` y'
In a case alternative: (D x', D y') -> D $ x' `op` y'
第二个:
Couldn't match type `Double' with `Int'
Expected type: Int
Actual type: a
In the second argument of `($), namely x' `op` y'
In the expression: I $ x' `op` y'
In a case alternative: (I x', I y') -> I $ x' `op` y'
我很确定我理解这两个错误的含义;我认为第一个是说我的类型签名中的信息不足以让 GHC 假设op
返回 a Double
,这是D
值构造函数所必需的,第二个是说由于第一行暗示a
是Double
,所以line 不能使用 type 的值,a
就好像它是一个Int
. 不过,我不知道从哪里开始寻找正确的方法。
如果它有帮助,我试图让它工作的原因是我正在跟随Write Yourself a Scheme 教程;本教程中的所有示例(特别是在评估部分中)仅处理整数,但作为练习,我想添加支持整数和浮点数的能力,以便例如(+ 1 2.5 2.5)
返回6.0
和(+ 1 2 3)
返回6
。如果我认为这是错误的方式或者有更简单的方法来完成它,我很想听听建议。