跳转到内容

Haskell/解决方案/列表和元组

来自维基教科书,开放的书籍,为开放的世界

← 返回列表和元组

构建列表

[编辑 | 编辑源代码]
练习
  1. 以下 Haskell 代码片段是否能正常工作:3:[True,False]?为什么或为什么不?
  2. 编写一个函数 cons8,它接受一个列表,并将其连接到 8 上。在以下列表上进行测试,方法如下:
    1. cons8 []
    2. cons8 [1,2,3]
    3. cons8 [True,False]
    4. let foo = cons8 [1,2,3]
    5. cons8 foo
  3. 以 8 位于列表末尾的方式调整上述函数
  4. 编写一个函数,它接受两个参数,一个列表和一个值,并将该值连接到列表上。你应该从以下开始:
     let myCons list thing =
  1. 这将无法正常工作。[True, False]是一个布尔值列表,3是一个整数。
  2. let cons8 list = 8:listlet cons8 = (:) 8let cons8 list = (:) 8 list 都是有效的函数。
    1. cons8 [] 返回 [8]
    2. cons8 [1,2,3] 返回 [8,1,2,3]
    3. cons8 [True,False] 会导致类型错误。这与练习 1 中的错误相同。
    4. let foo = cons8 [1,2,3] 不会输出任何消息,但 foo 为 [8,1,2,3]。试试看!
    5. cons8 foo(假设你完成了 2.4)返回 [8,8,1,2,3]
  3. 正如我们所知,let cons8 list = list:8 无法正常工作,因为 8 不是列表,但 let cons8 list = list ++ [8] 会正常工作,因为 (++) 会连接两个列表
  4. let myCons list thing = thing : listlet myCons list thing = (:) thing list 都是有效的函数。

列表中的列表

[编辑 | 编辑源代码]
练习
  1. 以下哪些是有效的 Haskell 代码,哪些不是?将其改写为连接表示法。
    1. [1,2,3,[]]
    2. [1,[2,3],4]
    3. [[1,2,3],[]]
  2. 以下哪些是有效的 Haskell 代码,哪些不是?将其改写为逗号和括号表示法。
    1. []:[[1,2,3],[4,5,6]]
    2. []:[]
    3. []:[]:[]
    4. [1]:[]:[]
    5. ["hi"]:[1]:[]
  3. Haskell 可以有列表的列表的列表吗?为什么或为什么不?
  4. 为什么以下列表在 Haskell 中无效?
    1. [[1,2],3,[4,5]]
  1. 1 和 2 不是有效的 Haskell 代码,3 是有效的
    1. 1:2:3:[]:[]123 是整数,而 [] 是一个列表。
    2. 1:(2:3:[]):4:[]。同样,14 是整数,而 2:3:[] 是一个整数列表。
    3. (1:2:3:[]):[]:[]。这是有效的 Haskell 代码,因为 1:2:3:[] 是一个整数列表,而 [] 是一个空列表(任何类型)。
  2. 前四个是有效的 Haskell 代码。第五个不是。
    1. [[],[1,2,3],[4,5,6]][1,2,3][4,5,6] 都是整数列表。整个列表是一个整数列表的列表。我们可以将一个空列表(任何类型)连接到它的前面。
    2. [[]]不是空列表!。这是一个包含一个空列表的列表。该列表本身不是空的,因为它有一个元素!
    3. [[],[]]。这是一个包含两个空列表的列表。
    4. [[1],[]]。这与前一个列表相同,只是第一个元素为 [1],而不是 []。由于该列表是一个列表的列表,它现在已成为一个整数列表的列表。
    5. [["hi"], [1]]。["hi"] 是一个字符列表,而 [1] 是一个整数列表。
  3. 是的,这是可能的。例如:[[[1],[2],[3]],[[4],[5],[6]],[[7],[8],[9]]]。为什么?你可以创建一个任何类型的列表!如果你已经有一个某种类型的列表,那么你可以创建一个该类型列表的列表。示例列表将写成:((1:[]):(2:[]):(3:[]):[]):((4:[]):(5:[]):(6:[]):[]):((7:[]):(8:[]):(9:[]):[]):[]
  4. 列表 [[1,2],3,[4,5]] 无效,因为它等效于 (1:2:[]):3:(4:5:[]):[],我们尝试连接不同类型的元素(即列表和数字)。Haskell 中的列表必须是类型同质的。有效的列表将是 [[1,2],[3],[4,5]],等效于 (1:2:[]):(3:[]):(4:5:[]):[]

不同的“多个”概念

[编辑 | 编辑源代码]
练习
  1. 写下第一个元素为 4、第二个元素为“hello”、第三个元素为 True 的 3 元组。
  2. 以下哪些是有效的元组?
    1. (4, 4)
    2. (4, "hello")
    3. (True, "Blah", "foo")
    4. ()
  3. 列表可以通过将新元素连接到它们来构建:你将一个数字连接到一个数字列表中,并将得到一个数字列表。事实证明,没有办法构建元组。
    1. 你认为这是为什么?
    2. 假设存在这样的函数。如果你在元组上“连接”一个值,你会得到什么?
  1. (4,"hello",True)
  2. 它们都是有效的!元组不受类型的限制。
    1. 一个包含两个整数的元组。
    2. 一个包含一个整数和一个字符串的元组。
    3. 一个包含一个布尔值和两个字符串的元组。
    4. 空元组 () 被称为“单位”
    1. 也许 Haskell 的创建者希望限制元组的功能,以避免过度使用它们。使用可连接的元组而不是列表和元组来提供函数参数的习惯,可能使函数变得更加复杂,因此更难阅读、编写和维护。
    2. 与列表不同,我们将获得一个具有不同类型的元组,因为元组的大小将更大。

元组在列表中和其他组合

[编辑 | 编辑源代码]
练习
  1. 以下哪些是有效的 Haskell 代码,为什么?
    • 1:(2,3)
    • (2,4):(2,3)
    • (2,4):[]
    • [(2,4),(5,5),('a','b')]
    • ([2,4],[2,2])
    • 无效。(2,3) 是一个元组,而连接 (:) 仅适用于列表。
    • 无效。(2,3) 是一个元组,而连接 (:) 仅适用于列表。
    • 有效。你将得到一个包含一个整数和一个整数的元组的列表:[(2,4)]
    • 无效。列表的所有元素必须是相同类型。(2,4)(5,5) 是包含一个整数和一个整数的元组,但 ('a','b') 是包含一个字符和一个字符的元组。
    • 有效。这是一个包含一个整数列表和一个整数列表的元组。

检索值

[编辑 | 编辑源代码]
练习
  1. 使用 fstsnd 的组合从元组 (("Hello", 4), True) 中提取 4。
  2. 正常的象棋记谱法与我们的记谱法略有不同:它将行编号为 1-8,将列编号为 a-h;并且列标签通常放在前面。我们可以用一个字符和一个数字来标记一个特定的点,比如 ('a', 4) 吗?这说明了与列表之间的什么重要区别?
  3. 编写一个函数,将列表的头部和尾部作为元组的第一个和第二个元素返回。
  4. 使用 headtail 编写一个函数,返回列表的第五个元素。然后,对其进行评论,指出你能够识别的任何问题和缺陷。
  1. snd (fst (("Hello", 4), True)) 返回 4
  2. 是的,我们可以!元组和列表之间的区别在于,列表的所有元素必须是相同类型(整数、布尔值等),但你可以向列表添加元素。元组的元素可以是任何你想要的类型,例如 (4, 'a') 中的整数和字符的元组,但你不能更改其大小。
  3. headAndTail list = (head list, tail list)
    
  4. fifthElement list = head (tail (tail (tail (tail list))))
    
    此实现的缺点包括定义的笨拙性、缺乏通用性(如果我们想获取第四个、第六个或第十九个元素呢?)、以及它会在传入一个元素少于五个的列表时导致程序崩溃的事实。

多态类型

[编辑 | 编辑源代码]
练习

为以下函数提供类型签名

  1. 上一节的第三个练习的解决方案(“...一个函数,将列表的头部和尾部作为元组的第一个和第二个元素返回”)。
  2. 上一节的第四个练习的解决方案(“...一个函数,返回列表的第五个元素”)。
  3. h x y z = chr (x - 2)(记住我们之前章节中讨论过 chr)。
  1. headAndTail :: [a] -> (a, [a])
    
  2. fifthElement :: [a] -> a
    
  3. h x y z :: Int -> a -> b -> Char -- y and z are not actually used, so their types could be anything
    
华夏公益教科书