跳轉到內容

另一個 Haskell 教程/勘誤

來自華夏公益教科書
Haskell
另一個 Haskell 教程
前言
簡介
入門
語言基礎 (解答)
型別基礎 (解答)
IO (解答)
模組 (解答)
高階語言 (解答)
高階型別 (解答)
單子 (解答)
高階 IO
遞迴
複雜度

此頁面包含一個錯誤列表,這些錯誤是在 YAHT 的 PDF 版本 中發現的(其中一些可能已經在 線上 HTML 版本 中修正了 - (匯入)).

  • 練習 3.1:"我們已經看到乘法比除法結合得更緊密。" - 就我而言,乘法和除法具有相同的優先順序,因此它們的結合程度相同。也許你指的是加法與乘法或乘法與乘方?我看到它已經在線上版本中修正了。
  • 練習 7.1 的解答(第 79 頁,在“7.3 部分應用”下)存在一個 bug,練習內容如下(參見 高階語言:部分應用 獲取對應的 HTML 版本(已修正))


練習

如果可能,將以下函式轉換為無點風格。

[...]

func5 f l = foldr (\x y -> f (y,x)) 0 l
  • 在第 81 頁,文字指出

"我們建立一個值,稱之為 x,其值為 Red。然後我們將它應用於 colorToRGB。我們檢查是否可以將 x 與 Red “匹配”。這種匹配失敗,因為根據 Eq Color 的定義,Red 不等於 Yellow。"

顯然,前提是錯誤的,為了使本段的其餘內容有意義,初始值 x 應該為 'Yellow'。


  • 根據 PDF 檔案 的第 172 頁,解決方案如下
[...]

func5 = foldr (uncurry $ flip f) 0

然而,正如 Michael Mossey 在 Haskell-Beginners 郵件列表中 指出的,該解決方案實際上是錯誤的。

以下是正確的解決方案

[...]

func5 = flip foldr 0 . flip . curry 

作為旁註,Daniel Fischer 已經 提供 了使用型別驗證解決方案正確性的簡潔方法,如下所示


檢查結果是否合理的一種簡單方法是

示例

Prelude> :t flip foldr 0 . flip. curry
flip foldr 0 . flip. curry :: (Num c) => ((c, b) -> c) -> [b] -> c

Prelude> :t \f list -> foldr (\x y -> f (y,x)) 0 list
\f list -> foldr (\x y -> f (y,x)) 0 list :: (Num b) =>
                                             ((b, a) -> b) -> [a] -> b

Prelude> :t \f -> foldr (uncurry $ flip f) 0
\f -> foldr (uncurry $ flip f) 0 :: (Num b1) =>
                                    (b -> a -> b1 -> b1) -> [(a, b)] -> b1

因此你可以看到你的結果具有正確的型別,而 Hal 的結果沒有。


在上面提到的描述中,前兩行中的第一對顯示

flip foldr 0 . flip. curry

(即,要驗證的解決方案) 的型別是

(Num c) => ((c, b) -> c) -> [b] -> c

後兩行中的第二對顯示

\f list -> foldr (\x y -> f (y,x)) 0 list

(即,本質上是練習中給出的表示式,即 f l = foldr (\x y -> f (y,x)) 0 l) 的型別也是

(Num b) => ((b, a) -> b) -> [a] -> b

(請注意,這與上面的型別相同,只是使用重新命名的變數)。

後兩行中的第三對顯示

\f -> foldr (uncurry $ flip f) 0

(即,Hal 在 PDF 版本 的教程中給出的解決方案) 的型別是

(Num b1) => (b -> a -> b1 -> b1) -> [(a, b)] -> b1

這是一個不同的型別。因此,Hal 給出的解決方案是錯誤的。

注意

(感謝 Michael Mossey 和 Daniel Fischer 在 Haskell-Beginners 郵件列表中就這個問題進行的討論)。

-- Benjamin L. Russell


2. 練習 4.11

練習
4.11. 測試 CPS 風格的 fold 是否模擬了 foldr 和 foldl 中的任何一個。如果沒有,差異在哪裡?

它沒有指定“CPS 風格的 fold”函式,因此讀者應該假設練習是關於之前定義的 cfold

cfold’ f z [] = z
cfold’ f z (x:xs) = f x z (\y -> cfold’ f y xs)
cfold f z l = cfold’ (\x t g -> f x (g t)) z l

但 YAHT 中給出的解決方案實際上不是關於此函式。事實上,此函式的行為與 foldr 完全相同。解決方案是關於非常相似的函式:唯一的區別是 cfold' 的第二種情況下的引數順序,即

cfold' f z (x:xs) = f z x (\y -> cfold' f y xs)
華夏公益教科書