跳轉到內容

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
    
華夏公益教科書