8

我是 Haskell 的初学者,我被undefined函数的类型签名吓了一跳。

我期待一些更简单的东西,但我在 Hackage 上找到了这个:

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

错误的特殊情况。预计编译器将认识到这一点并插入更适合undefined出现的上下文的错误消息。

你能解释一下这个签名是什么意思吗?

谢谢!

4

2 回答 2

7

对于初学者需要知道的所有方面,签名很简单

undefined :: a

a这意味着,与通常量化的类型变量(即任何小写字母)一样,也可以明确表示:

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

...或者,因为我更喜欢写它

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

量化被推断为对所有类型,即所有具有种类的事物*(阅读:“类型”,更准确地说是提升类型的种类——提升意味着它可以是懒惰的重击)。因此,您可以undefined在任何表达式中使用,无论需要什么类型。

现在,undefined当然是一个“部分函数”之类的东西,基本上是一个零参数的函数,它在任何地方都没有定义。(FTR,它不是函数,因为根据定义,函数具有参数[s]。)
您希望在实际评估它时获得有用的错误消息,但 GHC 默认情况下不会为所有内容生成调用堆栈(出于性能原因),因此过去的情况是错误消息几乎完全无用。这就是HasCallStack出现的地方:这是一个约束,它基本上告诉某些代码可能会在其中发生的上下文undefined,它应该注意它发生的位置,以便错误消息实际显示出来。所以,

undefined :: ∀ a. HasCallStack => a

HasCallStack出现在 the 之后有点令人困惑∀ a- 这实际上a与将使用的上下文无关undefined。只是,签名的形式总是

标识符::量词约束=>类型

并且HasCallStack是一个约束,这就是它出现在中间的原因。(更常见的是,约束实际上适用于您已量化的类型变量之一。)

最后,这个RunTimeRep东西是关于levity polymorphism的。我自己也不是很理解,但是在为什么未定义的函数 levity-polymorphic 与未装箱类型一起使用时讨论了它?

于 2019-05-26T14:29:27.737 回答
7

这是@leftaroundabout 答案的延续。

在 Haskell 中,值具有类型。但是类型本身也有类型。当一种类型充当另一种类型的类型时,我们称其为“种类”。

Haskell 中最重要和最常见的类型是Type,通常在签名中表示为*. 它是被“提升”的类型,也就是说,其值可以是 thunk,在评估时可能会发散、抛出错误等......例如,类型Int有 kind Type

还有其他类似的类型Int#没有解除。类型的值Int#永远不是thunk,它始终是内存中的实际值。

简而言之,值的内存表示由它们的类型控制。

RuntimeRep是另一种。它是和 之类的LiftedRep类型IntRep。这些类型没有任何值,它们的存在只是为了在类型级别表达事物,正如我们将看到的。

有一个超神奇的类型级实体称为TYPE它,当使用一种类型RuntimeRep(即使用描述内存中表示的类型)参数化时,返回其值具有该表示的类型的种类。例如,TypeTYPE LiftedRep,而种类Int#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所有函数中使用,无论是返回 kind 类型的Type函数,还是返回 kind 类型TYPE IntRep(换句话说:Int#类型)或返回另一个未提升类型的函数。否则,我们将需要多个不同版本的undefined,这会很烦人。

解决方案是制作undefined levity-polymorphic。签名说:对于任何可能的内存表示(RuntimeRep)和任何可能的类型,其值具有该表示,undefined计算该类型的成员。

于 2019-05-26T22:30:00.957 回答