这是@leftaroundabout 答案的延续。
在 Haskell 中,值有类型。但类型他们自己也有类型。当一种类型充当另一种类型的类型时,我们将其称为“种类”。
Haskell 中最重要和最常见的类型是Type http://hackage.haskell.org/package/base-4.12.0.0/docs/Data-Kind.html#t:Type,通常在签名中表示为*
。它是一种“提升”的类型,也就是说,其值可以是 thunk,在求值时可以发散、抛出错误等......例如类型Int
有善良Type
.
还有其他类型,例如Int# http://hackage.haskell.org/package/ghc-prim-0.5.3/docs/GHC-Prim.html#g:3那是not举起。类型的值Int#
is never一声重响,它始终是内存中的实际值。
简而言之,值在内存中的表示是受控按他们的类型。
RuntimeRep http://hackage.haskell.org/package/ghc-prim-0.5.3/docs/GHC-Types.html#t:RuntimeRep是另一种。它是这样的类型LiftedRep
and IntRep
。这些类型没有任何值,它们的存在只是为了在类型级别表达事物 https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/glasgow_exts.html?highlight=datakinds#extension-DataKinds, 正如我们将看到。
有一种超神奇的类型级实体叫做TYPE http://hackage.haskell.org/package/ghc-prim-0.5.3/docs/GHC-Types.html#t:TYPE当用 kind 的类型参数化时RuntimeRep
(即使用描述内存中表示的类型)返回其值具有该表示的类型。例如,Type
is TYPE LiftedRep
,而那种Int#
is 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
现在我们可以回到为什么undefined
有这么奇怪的签名。问题是,我们希望能够使用undefined
in all函数,无论是返回 kind 类型的函数Type
,还有返回 kind 类型的函数TYPE IntRep
(换句话说:Int#
type) 或返回另一个未提升类型的函数。否则,我们将需要多个不同版本的undefined
,这会很烦人。
解决方案是使undefined
轻率多态性。签名表示:对于任何可能的内存中表示(RuntimeRep
)并且对于任何可能的type其值具有该表示形式,undefined
计算该类型的成员。