简体   繁体   English

“未定义”的类型签名在Haskell中意味着什么?

[英]What does type signature for `undefined` mean in Haskell?

I am a beginner in Haskell and I am taken aback by the undefined function's type signature. 我是Haskell的初学者,我对undefined函数的类型签名感到吃惊。

I expected something more simple, but I found this on Hackage: 我期待更简单的东西,但我在Hackage上发现了这个:

undefined :: forall (r :: RuntimeRep). forall (a :: TYPE r). HasCallStack => a

A special case of error. 一个特殊的错误案例。 It is expected that compilers will recognize this and insert error messages which are more appropriate to the context in which undefined appears. 预计编译器将识别这一点并插入更适合于出现undefined的上下文的错误消息。

Could you please explain what does this signature mean? 你能解释一下这个签名是什么意思吗?

Thanks! 谢谢!

For all regards a beginner needs to know, the signature is simply 对于初学者需要知道的所有问题,签名很简单

undefined :: a

which means, as always with type variables (ie any lowercase letters) that a is universally quantified , which can also be made explicit: 这意味着,与通常使用类型变量(即任何小写字母)一样, a普遍量化的 ,也可以是明确的:

{-# LANGUAGE ExplicitForall #-}
undefined :: forall a. a

...or, as I prefer to write it ......或者,我喜欢写它

{-# LANGUAGE ExplicitForall, UnicodeSyntax #-}
undefined :: ∀ a. a

The quantification is infered to be over all types , ie all things with kind * (read: “type”, more accurate the kind of lifted types – lifted meaning it can be lazy thunk). 量化被认为是所有类型的 ,即所有类型的东西* (读:“类型”,更准确的类型提升类型 - 提升意味着它可以是懒惰的thunk)。 Therefore, you can use undefined in any expression, no matter what type is required. 因此,无论何种类型需要,您都可以在任何表达式中使用undefined

Now, undefined is of course a “partial function” like thing, basically a function which zero arguments which is defined nowhere. 现在, undefined当然是一个“部分函数”之类的东西,基本上是一个无处定义的零参数的函数。 (FTR, it's not a function, as a function by definition has argument[s].) (FTR,它不是一个函数,因为定义函数参数[s]。)
You'd like to get a useful error message when it is actually evaluated, but GHC doesn't by default produce a call stack for everything (for performance reasons), so it used to be the case that the error message was almost completely useless. 您希望在实际评估时获得有用的错误消息,但GHC默认情况下不会为所有内容生成调用堆栈(出于性能原因),因此过去的情况是错误消息几乎完全无用。 That's where the HasCallStack comes in: that's a constraint which essentially tells the context in which some code might incur undefined that it should note the place where it happens, in order for the error message to actually show it up. 这就是HasCallStack用武之地:这是一个约束,它实质上告诉了某些代码可能会发生undefined的上下文,它应该注意它发生的位置,以便错误消息实际显示出来。 So, 所以,

undefined :: ∀ a. HasCallStack => a

It's a bit confusing that the HasCallStack appears after the ∀ a – this doesn't really have anything to do with a but with the context in which undefined will be used. 这是一个有点令人困惑的是, HasCallStack后出现∀ a -这并不真的有什么关系a但在这背景下undefined将被使用。 Just, the form of signatures is always 只是,签名的形式总是如此

Identifier :: Quantifiers. Constraints => Type

and HasCallStack is a constraint, that's why it appears in the middle. HasCallStack是一个约束,这就是它出现在中间的原因。 (More often, constraints actually apply to one of the type variables you've quantified over.) (更常见的情况是,约束实际上适用于您量化的其中一个类型变量。)

Finally, this RunTimeRep stuff is about levity polymorphism . 最后,这个RunTimeRep东西是关于levity多态的 I don't really understand that myself, but it's discussed in Why is the undefined function levity-polymorphic when using it with unboxed types? 我自己并不是真的了解它,但是在将未使用的类型与未装箱的类型一起使用时为什么未定义的函数是levity-polymorphic?

This is a continuation of @leftaroundabout's answer. 这是@ leftaroundabout答案的延续。

In Haskell, values have types. 在Haskell中,值具有类型。 But types themselves also have types. 但类型本身也有类型。 When a type is acting as the type of another type, we call it a "kind". 当一个类型作为另一种类型的类型时,我们将其称为“种类”。

The most important and common kind in Haskell is Type , often denoted in signatures as * . Haskell中最重要和最常见的类型是Type ,通常在签名中表示为* It is the kind of types that are "lifted", that is, whose values can be thunks that, when evaluated, can diverge, throw an error, etc... For example the type Int has kind Type . 它是那种“被提升”的类型,也就是说,它的值可以是thonks,当被评估时,可以发散,抛出错误等等......例如Int类型有Type

There are also other types like Int# that are not lifted. 还有其他类型,如Int#没有解除。 A value of type Int# is never a thunk, it's always an actual value in memory. Int#类型的值永远不是thunk,它始终是内存中的实际值。

In short, the in-memory representation of values is controlled by their type's kind. 总之,值的内存中表示由它们的类型的种类控制的

RuntimeRep is another kind. RuntimeRep是另一种。 It is the kind of types like LiftedRep and IntRep . 它是LiftedRepIntRep等类型。 These types don't have any values, they exist merely to express things at the type level , as we shall see. 这些类型没有任何值,它们仅仅是为了在类型级别表达事物 ,我们将会看到。

There is a super-magical type-level entity called TYPE that, when parameterized with a type of kind RuntimeRep (that is with a type that describes an in-memory representation) returns the kind of types whose values have that representation. 有一个名为TYPE的超级魔法类型级实体,当使用类型RuntimeRep (具有描述内存中表示的类型)进行参数化时,返回其值具有该表示的类型。 For example, Type is TYPE LiftedRep , while the kind of Int# is TYPE IntRep . 例如, TypeTYPE LiftedRep ,而Int#TYPE IntRepTYPE IntRep

ghci> :set -XMagicHash
ghci> import GHC.Prim 
ghci> import GHC.Types
ghci> import Data.Kind
ghci> :kind (Int :: TYPE 'LiftedRep)
(Int :: TYPE 'LiftedRep) :: *
ghci> :kind Int#
Int# :: TYPE 'IntRep

Now we can get back to why undefined has such a weird signature. 现在我们可以回到为什么undefined有这么奇怪的签名。 The thing is, we want to be able to use undefined in all functions, be it functions that return types of kind Type , but also functions that return types of kind TYPE IntRep (in other words: the Int# type) or functions that return another unlifted type. 问题是,我们希望能够在所有函数中使用undefined ,无论是返回类型Type函数,还是返回TYPE IntRep (换句话说: Int#类型)或返回的函数另一种未提升的类型。 Otherwise, we would need multiple different versions of undefined , which would be annoying. 否则,我们需要多个不同版本的undefined ,这会很烦人。

The solution is to make undefined levity-polymorphic . 解决方案是使undefined levity-polymorphic The signature says: for any possible in-memory representation ( RuntimeRep ) and for any possible type whose values have that representation, undefined counts a member of that type. 签名表示:对于任何可能的内存中表示( RuntimeRep )以及其值具有该表示的任何可能类型undefined计算该类型的成员。

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

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