我需要一个函数来加倍列表中的每个其他数字.这样做的诀窍:
doubleEveryOther :: [Integer] -> [Integer]
doubleEveryOther [] = []
doubleEveryOther (x:[]) = [x]
doubleEveryOther (x:(y:zs)) = x : 2 * y : doubleEveryOther zs
Run Code Online (Sandbox Code Playgroud)
然而,问题是我需要从右边开始加倍每个其他数字- 所以如果列表的长度是偶数,那么第一个将加倍,等等.
我理解在Haskell中向后操作列表很棘手,所以我的计划是反转列表,应用我的函数,然后再次输出反向.我有一个reverseList功能:
reverseList :: [Integer] -> [Integer]
reverseList [] = []
reverseList xs = last xs : reverseList (init xs)
Run Code Online (Sandbox Code Playgroud)
但是我不太确定如何将它植入我原来的功能中.我得到这样的事情:
doubleEveryOther :: [Integer] -> [Integer]
doubleEveryOther [] = []
doubleEveryOther (x:[]) = [x]
doubleEveryOther (x:(y:zs)) =
| rev_list = reverseList (x:(y:zs))
| rev_list = [2 * x, y] ++ doubleEveryOther zs
Run Code Online (Sandbox Code Playgroud)
我不完全确定包含这样的中间值的函数的语法.
如果相关,则适用于CIS 194 HW 1中的练习2 .
这是您已经创建的两个函数的非常简单的组合:
doubleEveryOtherFromRight = reverseList . doubleEveryOther . reverseList
Run Code Online (Sandbox Code Playgroud)
请注意,您reverseList实际上已在标准Prelude中定义为reverse.所以你不需要自己定义它.
我知道上面的解决方案效率不高,因为两者都reverse需要通过整个列表.我将把它留给其他人来建议更高效的版本,但希望这说明了函数组合的功能,可以用更简单的计算来构建更复杂的计算.
正如Lorenzo指出的那样,您可以进行一次传递以确定列表是否具有奇数或偶数长度,然后进行第二次传递以实际构建新列表.但是,将两个任务分开可能更简单.
doubleFromRight ls = zipWith ($) (cycle fs) ls -- [f0 ls0, f1 ls1, f2 ls2, ...]
where fs = if odd (length ls)
then [(*2), id]
else [id, (*2)]
Run Code Online (Sandbox Code Playgroud)
那么这是如何工作的呢?首先,我们观察到要创建最终结果,我们需要将两个函数(id或(*2))中的一个应用于每个元素ls.zipWith如果我们有适当的功能列表,可以这样做.其定义的有趣部分基本上是
zipWith f (x:xs) (y:ys) = f x y : zipWith f xs ys
Run Code Online (Sandbox Code Playgroud)
如果f是($),我们只是在其他应用列表中的一个函数从一个列表中相应的元素.
我们想ls用无限的交替列表压缩id和(*2).问题是,该列表应该从哪个函数开始?它应该始终端与(*2),所以起始项目是由长度确定ls.奇怪的长度需要我们开始(*2); 一个,甚至一个id.
| 归档时间: |
|
| 查看次数: |
180 次 |
| 最近记录: |