【问题标题】:What is [] (list constructor) in Haskell?Haskell 中的 [] (列表构造函数)是什么?
【发布时间】:2011-01-17 05:40:21
【问题描述】:

我在理解函子时遇到问题,特别是 LYAH 中的 具体 类型是什么。我相信这是因为我不明白 [] 到底是什么。

fmap :: (a -> b) -> f a -> f b  
  1. [] 是类型构造函数吗?或者,它是一个值构造函数?
  2. 具有以下类型是什么意思:[] :: [a]
  3. Maybe类型构造函数还是Just值构造函数?
  4. 如果它像Just,那么Just 的签名怎么会像Just :: a -> Maybe a 而不是Just :: Maybe a,换句话说,为什么[] 没有输入[] :: a -> [a]
  5. LYAH 是这样说的,因为它适用于函子:注意我们没有在哪里编写 instance Functor [a],因为从 fmap :: (a -> b) -> f a -> f b 中,我们看到 f 必须是一个接受一种类型的类型构造函数。 [a] 已经是一个具体类型(其中包含任何类型的列表),而[] 是一个类型构造函数,它采用一种类型并可以生成诸如[Int][String] 甚至[[String]] 之类的类型。 虽然[] 的类型暗示它就像[a] 的文字,但我很困惑,LYAH 想要达到什么目的?

【问题讨论】:

  • 如果你想要 a -> [a] 类型的东西,有一个有趣的 (:[]) 函数。
  • ^ 或者你可以使用return(或pure或其他):D

标签: list data-structures haskell types


【解决方案1】:
  1. 它在语法上被重载为类型构造函数和值构造函数。

  2. 这意味着(值构造函数)[] 的类型对于所有类型a,它是a 的列表(写作[a])。这是因为每种类型都有一个空列表。

  3. 值构造函数[] 没有键入a -> [a],因为空列表没有元素,因此不需要a 来创建a 的空列表。请与Nothing :: Maybe a 进行比较。

  4. LYAH 谈论的是类型构造函数 [] 与类型 * -> *,而不是值构造函数 [] 与类型 [a]

【讨论】:

  • 知道[a][] a 的语法糖作为一种类型可能会有所帮助,这看起来更像是通常为更高种类的类型所做的事情。
【解决方案2】:
  1. 它是一个类型构造函数(例如,[Int] 是一个类型)和一个数据构造函数([2] 是一个列表结构)。
  2. 空列表是一个包含任何类型的列表
  3. [a] 类似于 Maybe a,[2] 类似于 Just 2。
  4. [] 是一个零元函数(常量),因此它没有函数类型。

【讨论】:

  • 真的喜欢 4 中的措辞。我认为结合了您对 4 的回答和 Doug 对 3 的回答,我才明白了这一点!所以Nothing :: Maybe a[] :: [a] 是空构造函数。 [a] 也是 Maybe a 的类似物,因为两者都是值的值构造函数(与 Nothing 离散)。结论,我被[] 弄糊涂了,因为[] 本质上将列表的数据构造函数与数组的Nothing 的数据构造函数重叠,而Maybe a 有两个独立的构造函数。我说的对吗?
【解决方案3】:

只是为了让事情更明确,这个数据类型:

data List a = Cons a (List a) 
            | Nil

...具有与内置列表类型相同的结构,但没有(更好,但可能令人困惑)特殊语法。以下是一些对应的样子:

  • List = [],类型构造函数类型为 * -> *
  • List a = [a],类型为*
  • Nil = [],具有多态类型的值分别为 List a[a]
  • Cons = :,分别为a -> List a -> List aa -> [a] -> [a]类型的数据构造函数
  • Cons 5 Nil = [5]5:[],单元素列表
  • f Nil = ... = f [] = ...,模式匹配空列表
  • f (Cons x Nil) = ... = f [x] = ...`,模式匹配单元素列表
  • f (Cons x xs) = ... = f (x:xs) = ...,模式匹配非空列表

事实上,如果你问 ghci 关于[],它会告诉你几乎相同的定义:

> :i []
data [] a = [] | a : [a]           -- Defined in GHC.Types

但是您不能自己编写这样的定义,因为列表语法及其“后缀”类型构造函数是一种特殊情况,在语言规范中定义。

【讨论】:

  • 你能解释一下最后一部分a:[a]而不是a:[]是空列表[]键入[a],定义data [] = [] | a : [a]的第一部分,让我去相信是[][],是否也满足[a]的要求?
  • 我不确定你在问什么。在a:[a] 中,: 定义数据构造函数(如Cons),[a] 指定构造函数的参数类型(如List a)。在定义的第一部分,[] 是一个没有参数的数据构造函数,如Nil。这两个部分都产生[a] 类型的值,因为这正是定义的内容!
  • 也许让你感到困惑的是数据构造函数不必将代表所有(或任何)参数的参数传递给类型构造函数?在data Either a b = Left a | Right b 中,数据构造函数Left a 仍会创建Either a b 类型的值,即使没有bNothing[] 也是如此。你甚至可以有类似data NoValue a b c d e f = Lonely 的东西。即使它没有任何值,Lonely 仍然被所有这些类型参数的幽灵所困扰,使其与任何具有不同类型的 Lonelys 不同。
【解决方案4】:

类型被描述为(在 GHCI 会话中):

$ ghci
Prelude> :info []
data [] a = [] | a : [a] -- Defined 

我们也可以认为它被定义为:

data List a = Nil
            | Cons a (List a)

data List a = EmptyList
            | ListElement a (List a)

类型构造函数

[a]是多态数据类型,也可以像上面写成[] a。这可能被认为是List a

在这种情况下,[] 是一个类型构造函数,它接受一个类型参数a 并返回类型[] a,也允许写为[a]

一个函数的类型可以写成:

sum :: (Num a) => [a] -> a

数据构造器

[] 是一个数据构造函数,它本质上意味着“空列表”。此数据构造函数不接受任何值参数。

还有另一个数据构造函数:,它将一个元素添加到另一个列表的前面。此数据构造函数的签名是 a : [a] - 它接受一个元素和另一个元素列表,并返回一个结果元素列表。

[] 表示法也可以用作构造列表的简写。通常我们会构造一个列表:

myNums = 3 : 2 : 4 : 7 : 12 : 8 : []

解释为

myNums = 3 : (2 : (4 : (7 : (12 : (8 : [])))))

但 Haskell 也允许我们使用简写

myNums = [ 3, 2, 4, 7, 12, 8 ]

含义相同,但外观稍好,符号。

二义性案例

有一个常见的模棱两可的情况:[a]。根据上下文,此表示法可以表示“a 的列表”或“只有一个元素的列表,即 a”。第一个含义是 [a] 出现在 type 中时的预期含义,而第二个含义是 [a] 出现在 value 中时的预期含义。

【讨论】:

  • 应该是sum :: (Num a) => [a] -> a(带有->)吗?
  • 在类型签名中使用[a][] a一样吗?
猜你喜欢
  • 2017-07-28
  • 2012-05-01
  • 2022-10-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-07-14
  • 2012-11-30
相关资源
最近更新 更多