[英]Type Signatures in Haskell
My question is regarding Type Signatures. 我的问题是关于类型签名。
The following code complies: 以下代码符合:
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)
However, I do not understand why substituting the above type signature (on line number 2) with the following does not work: 不过,我不明白为什么有以下不起作用取代上述类型签名(上2号线):
vMult :: (Num a) => Vector a -> Num -> Vector a
My understanding is that since m
is of type Num
(eg. the number 8
), and since i, j, k
are Num
as well, there should be no problems with computing Vector (i*m) (j*m) (k*m)
. 我的理解是因为
m
是Num
类型(例如数字8
),并且因为i, j, k
也是Num
,所以计算Vector (i*m) (j*m) (k*m)
应该没有问题Vector (i*m) (j*m) (k*m)
。
Kindly correct my understanding. 请理解我的理解。
Num a
isn't actually a type at all Num a
实际上根本不是一种类型 Num
is a type class, so if I say Num a
it means a
is a number type, so then Num
是一个类型类,所以如果我说Num a
它意味着a
是一个数字类型,那么
vMult :: (Num a) => Vector a -> a -> Vector a
means "as long as a
is a number type, vMult
takes a Vector of a
s and a single a
and returns a Vector of a
s." 装置“只要
a
是一个数字型, vMult
采用的矢量a
S和一个单一的a
,并返回的向量a
秒。”
That means that vMult
can work like 这意味着
vMult
可以像
vMult :: Vector Int -> Int -> Vector Int
or vMult :: Vector Int -> Int -> Vector Int
或
vMult :: Vector Double -> Double -> Vector Double
. vMult :: Vector Double -> Double -> Vector Double
。
Notice you get each type by replacing all the a
s in the original with a single number type. 请注意您更换所有的得到每种类型的
a
有一个单一的数字型在原有秒。
Num
on it's own doesn't make sense Num
就自己没有意义 Num
on its own would mean "is a number type", so if your function had the type signature Num
本身就意味着“是一个数字类型”,所以如果你的函数有类型签名
vMult :: (Num a) => Vector a -> Num -> Vector a
it would read "as long as a
is a number type, vMult
takes a Vector of a
s and an is a number type and returns a Vector of a
s." 它将读“只要
a
是一个数字型, vMult
采用的矢量a
S和一个是一个数字型和返回的向量a
秒。” It's ungrammatical in English just the same as it's an error in Haskell. 它在英语中是不合语法的,就像它在Haskell中的错误一样。
It's like saying "give me some butter and a has a sharp edge" instead of "give me some butter and a knife". 这就像是说“给我一些黄油,有一个锋利的边缘”,而不是“给我一些黄油和一把刀”。 The type signature that worked is like saying "find something you can spread with (call it k), and give me some butter and k."
有效的类型签名就像是说“找到你可以传播的东西(称之为k),并给我一些黄油和k。”
You also can't use Num a
instead of a
like Vector a -> Num a -> Vector a
because you can't put an assertion where you need a noun: "give me your key ring and a keys are made of metal so I can give you a new key ring". 你也不能使用
Num a
,而不是a
像Vector a -> Num a -> Vector a
,因为你需要一个名词,你不能把一个断言:“给我你的钥匙圈和钥匙由金属制成,以便我可以给你一个新的钥匙圈“。
Multiplication is defined on Num a
and Num a
ie 2 arguments of same Type belonging to Num
Typeclass. 乘法是在
Num a
和Num a
上定义的,即属于Num
Typeclass的相同Type的2个参数。
(*) :: (Num a) => a -> a -> a
If you only have Num
in your type signature, it would be akin to asking to allow multiplication to be done between say an Integer
and Float
because both are Types belonging to Typeclass Num
. 如果您的类型签名中只有
Num
,则类似于要求允许在Integer
和Float
之间进行乘法,因为两者都是属于Typeclass Num
类型。 That is why you need to to specify the Type that should be used amd not just the Typeclass
. 这就是为什么你需要指定应该使用的Type而不仅仅是
Typeclass
。
There is already a constraint to ensure that a
should belong to Num
when you use it for your Vector
. 当你将它用于
Vector
时,已经有一个约束来确保a
应该属于Num
。 In order to multiply each element in your Vector
with the chosen scalar, that scalar must not only belong to Num
but also be the same type ie a
. 为了将
Vector
每个元素与所选的标量相乘,该标量不仅必须属于Num
,还必须是相同的类型,即a
。
Num
is not a concrete type that can be used there. Num
不是可以在那里使用的具体类型 。 It is a unary type constructor that must be specialized with another type to be used. 它是一个一元类型的构造函数 ,必须专门使用另一种类型。 Speaking in OOP terms,
Num
is not a OOP-like abstract "superclass" type to be derived from, it's rather a factory that must be specialized for its usage. 用OOP术语来说,
Num
不是一个类似OOP的抽象“超类”类型,而是一个必须专门用于它的工厂。
So, trying to pass Num
to a place that requires kind ("type" of a type) *
is like trying to pass a function ( :: a -> b
) where a value ( :: c
) is required (the difference is that the former is done at type level): 因此,尝试将
Num
传递到需要类型的地方(类型的“类型”) *
就像尝试传递一个函数( :: a -> b
),其中需要一个值( :: c
)(区别在于前者是在类型级别完成的):
ghci> :kind Int
Int :: *
ghci> :kind Num
Num :: * -> Constraint
so we can see that application of Num
to any type of kind *
at time of type-check produces kind Constraint
and Constraint
may only be used before =>
in type signature (to limit what types are correct in position of a
in Vector a -> a -> Vector a
, that's the meaning of Constraint
). 所以我们可以看到该应用程序
Num
于任何类型的一种*
在类型检查的时候会产生一种Constraint
和Constraint
可能只有之前使用=>
在类型签名(限制什么类型在位置正确a
在Vector a -> a -> Vector a
,这就是Constraint
的意思)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.