我的问题是关于类型签名.
以下代码符合:
data Vector a = Vector a a a deriving (Show)
vMult :: (Num a) => Vector a -> a -> Vector a
(Vector i j k) `vMult` m = Vector (i*m) (j*m) (k*m)
Run Code Online (Sandbox Code Playgroud)
不过,我不明白为什么有以下取代上述类型签名(上2号线)不工作:
vMult :: (Num a) => Vector a -> Num -> Vector a
Run Code Online (Sandbox Code Playgroud)
我的理解是,既然m是类型Num(例如,数量8),由于i, j, k是Num为好,应该与计算没有问题Vector (i*m) (j*m) (k*m).
请理解我的理解.
Num a 实际上根本不是一种类型Num是一个类型类,所以如果我说它Num a意味着a数字类型,那么
vMult :: (Num a) => Vector a -> a -> Vector a
Run Code Online (Sandbox Code Playgroud)
意思是"只要a是一个数字类型,vMult取一个as和一个单一a的向量并返回一个as 的向量."
这意味着vMult可以像
vMult :: Vector Int -> Int -> Vector Int或那样工作
vMult :: Vector Double -> Double -> Vector Double.
请注意,通过a使用单个数字类型替换原始中的所有s来获取每种类型.
Num 它本身没有意义Num 单独表示"是一个数字类型",所以如果你的函数有类型签名
vMult :: (Num a) => Vector a -> Num -> Vector a
Run Code Online (Sandbox Code Playgroud)
它会读作"只要a是一个数字类型,vMult需要一个矢量as和一个数字类型并返回一个矢量as".它在英语中是不合语法的,就像它在Haskell中的错误一样.
这就像是说"给我一些黄油,有一个锋利的边缘",而不是"给我一些黄油和一把刀".有效的类型签名就像是说"找到你可以传播的东西(称之为k),并给我一些黄油和k."
你也不能使用Num a而不是a喜欢,Vector a -> Num a -> Vector a因为你不能把断言放在你需要名词的地方:"给我你的钥匙圈,钥匙是用金属制成的,所以我可以给你一个新的钥匙圈".