我对Haskell很新,所以我希望这不是一个愚蠢的问题.我有这种数据类型:
data N = I Int | D Double deriving (Show, Eq)
Run Code Online (Sandbox Code Playgroud)
我正在尝试使用签名编写一个函数,该函数(Num a) => (a -> a -> a) -> N -> N -> N将函数应用于Ns中的数字,并返回带有结果的N. 如果Ns都是Ds,它应该只应用函数并返回一个D; 如果一个人是一个I,另一个是D,它应该转换Int中I的Double,应用功能,两个DoubleS,并返回一个D; 如果两者都是Is,它应该应用该函数并返回一个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'
Run Code Online (Sandbox Code Playgroud)
不过,我在这两行都有错误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'
Run Code Online (Sandbox Code Playgroud)
第二个:
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'
Run Code Online (Sandbox Code Playgroud)
我很确定我明白这两个错误的含义; 我认为第一个是说我的类型签名中的信息不足以让GHC假设op返回a Double,这是D值构造函数所需要的,而第二个是说,因为第一行暗示的a是Double,这个line不能使用类型的值,a就好像它是一样Int.不过,我不知道从哪里开始寻找正确的方法.
如果它有帮助,我试图让它工作的原因是我正在跟随自己编写一个方案教程 ; 本教程中的所有示例(特别是在评估部分中)仅处理整数,但作为练习,我想添加支持整数和浮点数的能力,例如(+ 1 2.5 2.5)返回6.0和(+ 1 2 3)返回6.如果我以错误的方式思考这个问题,或者有更简单的方法来实现它,我很乐意听到建议.
签名
numOp :: (Num a) => (a -> a -> a) -> N -> N -> N
Run Code Online (Sandbox Code Playgroud)
说对于每个特定的实例和两个s numOp采用任何类型的单态函数,并从中计算出一个.例如,类型的函数a -> a -> aNumNN
Complex Float -> Complex Float -> Complex Float
Run Code Online (Sandbox Code Playgroud)
要么
approxRational :: RealFrac a => a -> a -> Rational
Run Code Online (Sandbox Code Playgroud)
(专门的a = Rational)将是合法的第一个论点.
你需要的是一个多态函数,它可以处理所有Num实例作为第一个参数,即rank 2类型
numOp :: (forall a. Num a => a -> a -> a) -> N -> N -> N
Run Code Online (Sandbox Code Playgroud)
(你需要RankNTypes语言扩展).