简体   繁体   English

描述非特定类型的 Haskell 函数的类型签名的方法是什么?

[英]What is the way to describe the type signature of Haskell functions that are not type-specific?

Given a function like negate , it has the type signature:给定一个 function 像negate ,它具有类型签名:

negate :: Num a => a -> a

which I would describe as a being the type in the context of Num (correct me if you think I am wrong).我将其描述a Num上下文中的类型(如果您认为我错了,请纠正我)。

But I not fully sure how to describe something like last , which has the type signature:但我不完全确定如何描述类似last的东西,它具有类型签名:

last :: [a] -> a

My guess would be to say it isn't type-specific, and that it takes a list and produces a single value of the same type as the list.我的猜测是说它不是特定于类型的,它需要一个列表并产生与列表相同类型的单个值。 Is this the correct way to think about it?这是正确的思考方式吗?

First, a is not the type in the context of Num , but a type that has a Num instance.首先, a不是Num上下文中类型,而是具有Num实例的类型。

Num a => a -> a is a constrained polymorphic type, while [a] -> a is an unconstrained polymorphic type, or just polymorphic type for short. Num a => a -> a是受约束的多态类型,而[a] -> a是不受约束的多态类型,简称多态类型。 In the unconstrained case, a can be any type;在不受约束的情况下, a可以是任何类型; in the constrained case, it must be a type that obeys the given constraints.在受约束的情况下,它必须是服从给定约束的类型。

In negate you need to operate on the element passed, in your case you could apply some operator to it, eg (-) : negate a = -a .negate中,您需要对传递的元素进行操作,在您的情况下,您可以对其应用一些运算符,例如(-) : negate a = -a

You cannot define negate for any type, because you need to be able to call (-) on it.您不能为任何类型定义negate ,因为您需要能够对其调用(-) You need some guarantee that the argument given will be of some type which supports this operation.您需要保证给定的参数将是支持此操作的某种类型。

Num is a type class which gives you exactly this - a compile-time guarantee that (-) is supported, and other functions like + , * , too. Num是一种类型 class ,它为您提供了这一点 - 编译时保证(-)支持,以及其他功能,如+* ,等等。 You can read more about it in the docs您可以在文档中阅读更多相关信息

In contrast, last:: [a] -> a does not (need to) do anything on the actual a values.相反, last:: [a] -> a不会(不需要)对实际a值做任何事情。 It only accepts them and returns the last one.它只接受它们并返回最后一个。 While negate operates on the a value, here last operates on the list , but does not do anything to its values, it only passes them around.虽然negatea值进行操作,但这里lastlist进行操作,但不对它的值做任何事情,它只是传递它们。 Therefore, it does not need any knowledge about them, and so the type is unconstrained.因此,它不需要任何关于它们的知识,因此类型不受限制。

last:: [a] -> a is the Haskell98 syntax for the System F type last:: [a] -> aSystem F类型的 Haskell98 语法

last :: ∀ a. [a] -> a

The ∀ a can be understood as a kind of type-level lambda binding, ie before the actual value level list parameter the function accepts a type-level argument telling what the type of elements contained in the list. ∀ a可以理解为一种类型级别的 lambda 绑定,即在实际值级别列表参数之前 function 接受一个类型级别参数,告诉列表中包含的元素的类型。 This universal quantification makes the function parametrically polymorphic .这种通用量化使得 function参数化多态

Normally, the type variables are automatically inserted by the type checker.通常,类型变量由类型检查器自动插入。 In newer GHC Haskell, you can also explicitly apply them:在较新的 GHC Haskell 中,您还可以显式应用它们:

Prelude> :set -XTypeApplications 
Prelude> :t last @Int
last @Int :: [Int] -> Int
Prelude> last @Double [5,6,7]
7.0

negate is also parametrically polymorphic, but unlike last it does not work truely “for all” types, but only for those that have a Num instance (which both Int and Double do, but not eg Char ). negate在参数上也是多态的,但与last不同的是,它不能真正“适用于所有”类型,而仅适用于具有Num实例的那些( IntDouble都可以,但不是例如Char )。 In other words, it accepts not only an extra argument specifying the type, but also a proof that it does indeed have a Num instance.换句话说,它不仅接受指定类型的额外参数,还接受它确实有一个Num实例的证明 That too will be inserted automatically by the compiler.这也将由编译器自动插入。

negate :: ∀ a. Num a => a -> a
Prelude> :t negate @Int
negate @Int :: Int -> Int
Prelude> :t negate @Char

<interactive>:1:1: error:
    No instance for (Num Char) arising from a use of ‘negate’

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

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