【发布时间】:2020-12-14 20:03:21
【问题描述】:
this pdf 的练习 2 内容如下:
一旦我们有正确顺序的数字,我们需要将每个数字加倍 另一个。定义一个函数
doubleEveryOther :: [Integer] -> [Integer]请记住 doubleEveryOther 应该每隔一个加倍 从右开始的数字,即倒数第二个, 倒数第四个,...数字翻了一番。
我创建了一个实现,但它没有达到我的预期。这是我的代码:
doubleEveryOther'' :: [Integer] -> [Integer]
doubleEveryOther'' [] = []
doubleEveryOther'' [x] = [x]
doubleEveryOther'' s@(_:_:_) =
let x:y:xs = reverse s
in reverse (x : 2 * y : doubleEveryOther'' xs)
以及它运行的一些示例:
*Main> doubleEveryOther'' [1,2,3,4,5,6,7,8,9]
[1,4,3,8,5,12,7,16,9]
*Main> doubleEveryOther'' [1,2,3,4,5,6,7,8]
[1,4,3,8,10,6,14,8]
不过,我期待
*Main> doubleEveryOther'' [1,2,3,4,5,6,7,8,9]
[1,4,3,8,5,12,7,16,9]
*Main> doubleEveryOther'' [1,2,3,4,5,6,7,8]
[2,2,6,4,10,6,14,8]
您会看到,在条目数量为偶数的情况下,它会部分地通过序列发生故障。我的猜测是我没有正确处理列表项 [] 的结尾,或者我没有正确使用 as-pattern。
【问题讨论】:
-
在整个计算过程中你应该只需要两次
reverse。现在,您在每次递归调用时都在反转列表,这看起来很奇怪。错误的结果有可能是在错误的时间倒车太多造成的。 -
这里有一个可以帮助你的观察。假设
doubleEveryOther''做了它想要做的事情:它将从其参数末尾开始的所有其他元素加倍。现在请注意,xs与参数相比顺序相反;所以doubleEveryOther'' xs是从xs末尾开始的所有其他元素的两倍——但这是从原始参数的 start 开始的所有其他元素! -
这些是有用的提示。在我目前的水平上,很难确定事情发生在哪里。这就说得通了。此外,由于 reverse 有 2 个状态,并且我们正在对每个其他元素做一些事情,所以周期为 4 是有道理的。
标签: haskell as-pattern