应用具有Ints或Doubles参数的函数

时间:2012-12-31 01:11:01

标签: haskell types

我对Haskell很新,所以我希望这不是一个愚蠢的问题。我有这种数据类型:

data N = I Int | D Double deriving (Show, Eq)

我正在尝试编写一个带有签名(Num a) => (a -> a -> a) -> N -> N -> N的函数,该函数将函数应用于N中的数字,并返回带有结果的N.如果N s都是D s,则应该只应用该函数并返回D;如果一个是I而另一个是D,它应该将Int中的I转换为Double,将该函数应用于两个Double D,然后返回I;如果两者都是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'

第二个:

op

我很确定我明白这两个错误的含义;我想第一个是说我的类型签名中的信息不足以让GHC假设Double返回D,这是a值构造函数所需要的,并且第二行是说,因为第一行暗示Doublea,所以此行不能使用Int类型的值,就好像它是(+ 1 2.5 2.5)一样。我不知道从哪里开始寻找正确的方法来做到这一点。

如果有帮助,我试图让它发挥作用的原因是我跟随Write Yourself a Scheme tutorial;本教程中的所有示例(特别是在Evaluation section中)仅处理整数,但作为练习,我想添加支持整数和浮点数的能力,以便例如6.0返回(+ 1 2 3)6返回{{1}}。如果我以错误的方式思考这个问题,或者有更简单的方法来实现它,我很乐意听取建议。

1 个答案:

答案 0 :(得分:7)

签名

numOp :: (Num a) => (a -> a -> a) -> N -> N -> N

表示numOpa -> a -> aNum的每个特定实例提供N类型的任何单态函数,并从该计算中获取N。例如,类型

的函数
Complex Float -> Complex Float -> Complex Float

approxRational :: RealFrac a => a -> a -> Rational

(专门针对a = Rational)将是合法的第一个论点。

你需要的是一个多态函数,它可以处理所有Num个实例作为第一个参数,即rank 2类型

numOp :: (forall a. Num a => a -> a -> a) -> N -> N -> N

(您需要RankNTypes语言扩展名。)