[英]Type Signatures in Haskell
我的问题是关于类型签名。
以下代码符合:
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)
不过,我不明白为什么有以下不起作用取代上述类型签名(上2号线):
vMult :: (Num a) => Vector a -> Num -> Vector a
我的理解是因为m
是Num
类型(例如数字8
),并且因为i, j, k
也是Num
,所以计算Vector (i*m) (j*m) (k*m)
应该没有问题Vector (i*m) (j*m) (k*m)
。
请理解我的理解。
Num a
实际上根本不是一种类型 Num
是一个类型类,所以如果我说Num a
它意味着a
是一个数字类型,那么
vMult :: (Num a) => Vector a -> a -> Vector a
装置“只要a
是一个数字型, vMult
采用的矢量a
S和一个单一的a
,并返回的向量a
秒。”
这意味着vMult
可以像
vMult :: Vector Int -> Int -> Vector Int
或
vMult :: Vector Double -> Double -> Vector Double
。
请注意您更换所有的得到每种类型的a
有一个单一的数字型在原有秒。
Num
就自己没有意义 Num
本身就意味着“是一个数字类型”,所以如果你的函数有类型签名
vMult :: (Num a) => Vector a -> Num -> Vector a
它将读“只要a
是一个数字型, vMult
采用的矢量a
S和一个是一个数字型和返回的向量a
秒。” 它在英语中是不合语法的,就像它在Haskell中的错误一样。
这就像是说“给我一些黄油,有一个锋利的边缘”,而不是“给我一些黄油和一把刀”。 有效的类型签名就像是说“找到你可以传播的东西(称之为k),并给我一些黄油和k。”
你也不能使用Num a
,而不是a
像Vector a -> Num a -> Vector a
,因为你需要一个名词,你不能把一个断言:“给我你的钥匙圈和钥匙由金属制成,以便我可以给你一个新的钥匙圈“。
乘法是在Num a
和Num a
上定义的,即属于Num
Typeclass的相同Type的2个参数。
(*) :: (Num a) => a -> a -> a
如果您的类型签名中只有Num
,则类似于要求允许在Integer
和Float
之间进行乘法,因为两者都是属于Typeclass Num
类型。 这就是为什么你需要指定应该使用的Type而不仅仅是Typeclass
。
当你将它用于Vector
时,已经有一个约束来确保a
应该属于Num
。 为了将Vector
每个元素与所选的标量相乘,该标量不仅必须属于Num
,还必须是相同的类型,即a
。
Num
不是可以在那里使用的具体类型 。 它是一个一元类型的构造函数 ,必须专门使用另一种类型。 用OOP术语来说, Num
不是一个类似OOP的抽象“超类”类型,而是一个必须专门用于它的工厂。
因此,尝试将Num
传递到需要类型的地方(类型的“类型”) *
就像尝试传递一个函数( :: a -> b
),其中需要一个值( :: c
)(区别在于前者是在类型级别完成的):
ghci> :kind Int
Int :: *
ghci> :kind Num
Num :: * -> Constraint
所以我们可以看到该应用程序Num
于任何类型的一种*
在类型检查的时候会产生一种Constraint
和Constraint
可能只有之前使用=>
在类型签名(限制什么类型在位置正确a
在Vector a -> a -> Vector a
,这就是Constraint
的意思)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.