简体   繁体   English

在Haskell中键入签名

[英]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) . 我的理解是因为mNum类型(例如数字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。”

Facts aren't types 事实不是类型

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 ,而不是aVector 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 aNum 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 ,则类似于要求允许在IntegerFloat之间进行乘法,因为两者都是属于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于任何类型的一种*在类型检查的时候会产生一种ConstraintConstraint可能只有之前使用=>在类型签名(限制什么类型在位置正确aVector a -> a -> Vector a ,这就是Constraint的意思)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM