Haskell中的Nothing是什么类型?

27

我正在阅读《Haskell函数式编程入门》一书的第118页,内容涉及it技术。

书中写道:

ghci> :t Nothing 
Nothing :: Maybe a

这是我的问题:
如果我理解正确,Nothing 是一个值,只有具体类型才能有值,但 Maybe a 不是具体类型。那么它怎么可能有 Nothing 这个值呢?
书中还说:
请注意,Nothing 的类型是 Maybe a。它的类型是多态的。
什么是多态类型?我该如何理解?这是否与只有具体类型才能有值的规则相矛盾?
编辑:
从书的 PDF 版本中:
我们说一个类型是具体的,如果它根本不需要任何类型参数(例如Int或Bool),或者如果它需要类型参数并且它们都填充了(例如Maybe Char)。 如果你有一些值,它的类型总是具体类型。

2
挺有趣的问题。Nothing不是一个值,而是构造函数。构造函数是一种特定类型的值(嗯,并不是完全准确的说法),它是一个函数。 - user3974391
函数是某种类型的值?我该如何理解这个?您能否详细解释一下您的意思? - jhegedus
8
"Maybe" 不是一个具体类型,不能有实际的值。对于任何 a,"Maybe a" 都是一个具体类型。对于任何 a,"Nothing" 都是 "Maybe a" 的一种值。 - Sassa NF
6
这本书定义了“具体类型”指的是“完全应用的类型构造器”,或者更正式地说,这是kind为*的类型。这似乎是导致所有混淆的原因。根据该书的定义,Maybe a是具体类型,而仅有的Maybe则不是。因此,NothingMaybe a类型绝对没有问题。话虽如此,“具体”并不是官方术语,每个人使用它的方式也都不同。 - kosmikus
1
这有点微妙,我在这方面远非最有知识的人,但我确信,在Haskell底层语言(lambda演算的一种变体)中,“Nothing”实际上是类型为“/\a. Maybe a”的,这意味着如果您给它一个具体的类型“a”,您将得到具体类型“Maybe a”的值。然而,在Haskell中,这种类型“a”的传递是隐含的。 - Tom Ellis
这意味着存在一些不具体的类型?也许 Maybe alone 是一个不具体的类型?我以为 Maybe alone 根本就不是一个类型,而是一个类型构造函数。 - jhegedus
5个回答

16

这并不矛盾。 Nothing是一个值,其具体类型可以是Maybe a的任何可能实例。

换句话说,Maybe a类型的值继续具有具体类型Maybe IntMaybe StringMaybe Whatever,特别地,取决于上下文,Nothing能够被它们中的每一个类型赋值。因为它的构造函数,也称为Nothing :: Maybe a,不需要任何参数,因此可以直接调用以生成Maybe a类型的值。如果您愿意,对于每种具体类型,我们将会有一个这样的值。

当然,在没有上下文的情况下,ghci会给出它可以推导出的最通用类型Maybe a,但这不是它的具体类型,这将取决于您将在其中使用Nothing的个别表达式。例如:

ghci> Nothing
Nothing
it :: Maybe a

这可能是您键入的内容,或类似于此的内容。由于没有进一步的上下文,因此 Nothing 不会以具体类型键入。

ghci> Nothing :: Maybe Int
Nothing
it :: Maybe Int

在这里,我强制它假定具体类型为Maybe Int

ghci> 1 + fromMaybe 2 Nothing
3
it :: Integer

如果我将它与一些整数相加(fromMaybe :: a -> Maybe a -> a 接受默认值和 Maybe a 并返回 Just 中的值或 Nothing 的默认值), 那么系统将把 Nothing 归类为 Maybe Integer,因为您希望从中提取一个整数。但是这里没有整数,所以在这种情况下,我们将 1 与默认值 2 相加。

ghci> 1 + fromMaybe 2 (Nothing :: Maybe Integer)
3
it :: Integer

我也是这样做的,为了进行二次检查。我们强制Nothing在同一个表达式中具有我们先前假定的具体类型。


ghci> 1 + fromMaybe 2 (Nothing :: Maybe Char)

<interactive>:1:15:
    No instance for (Num Char)
      arising from the literal `2'
    Possible fix: add an instance declaration for (Num Char)
    In the first argument of `fromMaybe', namely `2'
    In the second argument of `(+)', namely
      `fromMaybe 2 (Nothing :: Maybe Char)'
    In the expression: 1 + fromMaybe 2 (Nothing :: Maybe Char)

为了三次检查,如果我们强制它假设另一种具体类型,你会发现它的值完全不同,导致类型错误(与C不同,在Haskell中,Char不作为数字)。


GHCI说Nothing的类型是Maybe a,但是Maybe a是什么? - jhegedus
根据用户3974的说法,"Nothing"不是一个值,而是一个构造函数...嗯。 - jhegedus
那么 Nothing 本身没有具体的类型?那么 Nothing 是什么类型?这种类型被称为什么类型? - jhegedus
1
多态 :) 就像 Just :: a -> Maybe a 是一个多态构造器一样。 - Riccardo T.
10
关于 "concrete" 这个词,我认为存在一些疑惑。我更经常看到 "concrete" 被用来表示 "ground type",即 Kind * 的类型。在这个意义上,"Maybe a" 完全是 concrete - 它只是 polymorphic 的 ground type。而在此处,您使用 concrete 来表示 monomorphic。我认为 OP 的某些困惑部分在于这两种不相关的 "concrete" 词义。OP 引用的 LYAH 摘录是使用 "concrete" 来表示具有 Kind * 的意义。 - drquicksilver

6

这不是与只有具体类型才能拥有值的规则相矛盾吗?

由于函数在Haskell中是一等值(first-class values),这个所谓的规则意味着像mapfoldr这样的多态函数将不可能实现。

实际上,Haskell中有很多多态非函数值,例如

1 :: Num a => a
Nothing :: Maybe a
[] :: [a]
Left 1 :: Num a => Either a b

等等,这些值对于每个 a (和 b) 的实例都存在。


所以结论是,不仅具体类型可以具有值?那么这本书的陈述(请参见EDIT)是不正确的吗?那么,“Maybe a”是一种多态类型(即不是具体类型),我理解得对吗?“多态类型”是表示诸如“Maybe a”之类概念的正确术语吗? - jhegedus
7
看起来这本书指的是完全应用的具体含义。forall a. Maybe a 是一个完全应用的类型,可以绝对有值。而 Maybe 不是,因此不存在值 v :: Maybe - daniel gratzer
所以结论是,Nothing 的类型可能是 Maybe a? - jhegedus
@jhegedus:是的(就像GHC所说的)。 - Antal Spector-Zabusky

3
在某种意义上,你是对的。并没有类型为forall a.Maybe a的值。你构造的每个Maybe值实际上都有一些明确的类型Maybe tau,其中tau可能已知或未知,但是一定是某个确定的类型。
符号Nothing :: forall a.Maybe a告诉我们,每当使用表达式Nothing时,它将构造一个预期的Maybe类型的值。

1
@jhegedus 我之前告诉过你:在这种情况下,它的意思是“无论你想要什么具体的 Maybe 类型,它都会为你创建”。或者更正式地说:对于你可能想要的任何 a,Nothing 都会给你 Maybe a。也就是说,如果你想要一个 Maybe StringNothing 就会给你一个 Maybe String。对于 Int 或其他任何类型也是如此。 - Ingo
当然,多态类型也有值。Nothing 是类型 forall a. Maybe a 的一个值,就像 \ x -> x 是类型 forall a. a -> a 的一个值一样。 - kosmikus
@kosmikus 好的,我建议你给我展示一些代码,其中一个表达式 Nothing 被声称在类型 forall a.Maybe a 中使用,然后我会告诉你那个 Nothing 的真实类型,它不会是 forall a. Maybe a。 - Ingo
@Ingo 好的,虽然我认为在像 Haskell 这样表面上没有显式类型应用的语言中这种区分没有意义,但是对于 let f :: (forall a. Maybe a) -> Bool; f _ = True in f Nothing 呢? - kosmikus
@kosmikus 这次你抓住我了 :) 但这已经需要更高级别的类型了,不是吗。 - Ingo
显示剩余5条评论

1

Maybe类型有两个构造器:Nothing和Just a,其中a是一个类型变量。Nothing本身并不确定(约束)类型,但在任何合理的上下文中都会找到类似于以下内容的东西(我不声称它是语法正确的Haskell,但这是10年前我可能会写的东西):

if (foo == 5)
then Nothing
else Just 5

然后类型推断会告诉你,假设5是此代码片段‘foo’的参数,类型为Int,那么foo的类型为:

foo :: Int -> Maybe Int

但是正如前面的帖子所指出的那样,也许a是一个完全合适的类型。您可以在[]中找到相同的非问题,即使用[](空列表的构造函数)与列表类型。


0

这个在26:00的演讲回答了一个问题:" [ ] 的类型是什么?",这是与 " Nothing 的类型是什么?" 相关的问题。

此外,Hudak的书中也有一段很好的描述:

enter image description here


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接