[a]究竟代表什么?

时间:2013-07-31 15:59:05

标签: haskell

我正在做一些来自“真实世界Haskell”的练习。一个是设计init :: [a] -> [a]的安全版本。

我应该从safeInit :: [a] -> Maybe [a]

开始

这就是我现在所拥有的。

safeInit :: [a] -> Maybe [a]
safeInit [] = Nothing
safeInit [a] = if length [a] <= 1
    then Nothing
    else Just (take (length [a] -1) [a])

在GCHi中,当测试safeInit [1,2]时,我收到错误消息

  

* 异常:ch4exercise.hs:(21,1) - (24,44):函数safeInit中的非详尽模式

我的印象是[a]只代表a的列表(任意大小)。我做错了什么?

4 个答案:

答案 0 :(得分:14)

作为一种类型,[a]代表“任意大小的a s列表”。但是,作为一种模式,[a]代表“一个只包含一个元素的列表,此后将以名称a”知道。类似地,[a,b]将表示“包含两个元素的列表,其中第一个应被称为a,第二个应被称为b”等等。正如您已经知道的那样,[]代表“一个包含0个元素的列表”。

这类似于将列表文字作为表达式编写的方式。即如果你写myList = []myList是空列表,如果你写myList = [x]myList是一个只包含一个元素的列表,它是变量{{的值1}}。

答案 1 :(得分:4)

[]是空列表,一个不包含任何内容的列表。 [a]是一个只包含一个元素的列表,该元素(不是列表)将在函数中标识为“a”。 因此,您仍需要考虑列表包含多个元素的情况。

如果您只使用“a”而不是“[a]”,那么“a”将引用整个列表,您可以开始将它与您必须使用的功能分开。

请注意,您已经处理了空列表的情况,因此您不需要在if语句中再次检查它。

答案 2 :(得分:3)

在Haskell中你必须习惯的一件事,在你有经验之前不是很直观,是类型级事物的“命名空间”与值级别的名称空间完全分开的东西。这意味着当你谈论类型时,相同的源文本可能具有完全不同的含义,而不是在谈论价值时。

safeInit :: [a] -> Maybe [a]

::之后的所有内容都在谈论类型。此处[a]是应用于类型变量a的列表类型构造函数 1 因此它是列表的类型 (任何大小)其元素的类型为a

safeInit [a] = if length [a] <= 1
    ...

OTOH此等式位于级别。这里[a]不是类型,它是(在=的左侧,它是一个与之匹配的模式应用safeInit的值;在右侧,它只是一个值)。在值级别,方括号语法不是列表类型构造函数,它是用于编写列表的语法糖,列表中的所有元素用括号内的逗号分隔。所以[a]是包含一个单独元素的列表的值,由变量a表示。如果我们希望列表为空,我们会写[]。如果我们希望列表只包含ab,我们会写[a, b]等等。

在价值级别,[a]成为任意数量a的列表没有多大意义,因为(在此代码的任何特定评估期间)a是一个特定值,例如3.4。对于任意数量的3.4 s列表的表达式有什么用处?


1 正如Maybe a是应用于类型变量Maybe的{​​{1}}类型构造函数一样;列表类型构造函数唯一特别之处在于它被称为a而不是普通名称,并且为应用程序而不是通常的前缀形式获取这种奇怪的“周围”语法。

答案 3 :(得分:0)

这条线存在问题:

safeInit [a] = if length [a] <= 1

在等式的左侧,[a]将匹配具有恰好一个元素的列表。因此编译器会看到一个空列表的版本为safeInit,一个元素的列表的版本为safeInit,但对于包含更多元素的列表则没有。这就是为什么它抱怨Non-exhaustive patterns

我认为你真正想要的是

safeInit a = if length a <= 1
    then Nothing
    else Just (take (length a -1) a)

总结:

  • 在类型签名中,[a]代表任意类型a的元素列表。

  • 在模式中,[a]匹配一个只有一个元素的列表。