[英]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
. 它是LiftedRep
和IntRep
等类型。 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
. 例如, Type
是TYPE LiftedRep
,而Int#
的TYPE IntRep
是TYPE 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.