简单Haskell函数中的中间值

Jos*_*der 1 haskell

我需要一个函数来加倍列表中的每个其他数字.这样做的诀窍:

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 .

Rob*_*ond 7

这是您已经创建的两个函数的非常简单的组合:

doubleEveryOtherFromRight = reverseList . doubleEveryOther . reverseList
Run Code Online (Sandbox Code Playgroud)

请注意,您reverseList实际上已在标准Prelude中定义为reverse.所以你不需要自己定义它.

我知道上面的解决方案效率不高,因为两者都reverse需要通过整个列表.我将把它留给其他人来建议更高效的版本,但希望这说明了函数组合的功能,可以用更简单的计算来构建更复杂的计算.


che*_*ner 5

正如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.