另一个 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)
YAHT 从未经过全面校对,因此这只是一个部分列表。 |
这仍然是一个正在进行的工作。请随时根据需要添加内容! |