Haskell:列表中的每个第2个元素加倍

时间:2013-06-29 18:02:07

标签: haskell

我刚刚开始使用Haskell并想编写一个函数,给定一个列表,返回一个列表,其中每个第二个元素都被加倍。

到目前为止,我已经想出了这个:

double_2nd :: [Int] -> [Int]
double_2nd [] = []
double_2nd (x:xs) = x : (2 * head xs) : double_2nd (tail xs)

哪个有效,但我想知道你们怎么会写这个功能。是否有更常见/更好的方式或看起来是对的?

6 个答案:

答案 0 :(得分:42)

这还不错,以修正建议为模。一旦你越来越熟悉基础库,你可能会避免使用显式递归来支持某些更高级别的函数,例如,你可以创建一个函数列表,其中每个函数都是*2并应用(zip)您的数字列表中的函数列表:

double = zipWith ($) (cycle [id,(*2)])

答案 1 :(得分:19)

你可以避免"空列表"一些智能模式匹配的异常。

double2nd (x:y:xs) = x : 2 * y : double2nd xs
double2nd a = a

这只是以下

的语法糖
double2nd xs = case xs of
    x:y:xs -> x : 2 * y : double2nd xs
    a -> a

模式匹配按顺序完成,因此xs将首先与模式x:y:xs匹配。然后,如果失败,那么catch-all模式a将会成功。

答案 2 :(得分:9)

一点点的死灵法术,但我认为这种方法对我来说非常好,并希望分享:

double2nd n = zipWith (*) n (cycle [1,2])

zipWith接受一个函数,然后将该函数应用于两个列表中的匹配项(第一项到第一项,第二项到第二项等)。函数是乘法,压缩列表是1和2的无限循环。 zipWith(以及所有zip变体)在较短列表的末尾停止。

答案 3 :(得分:4)

在奇怪的名单上试试:

Prelude> double_2nd [1]
[1,*** Exception: Prelude.head: empty list

您可以看到代码存在问题。 “头部”和“尾部”从来都不是一个好主意。

答案 4 :(得分:0)

对于奇数列表或double_2nd [x],您可以随时添加

git push <remote-name> <remote-branch>

谢谢。

答案 5 :(得分:0)

这里是foldr-based solution

bar :: Num a => [a] -> [a]
bar xs = foldr (\ x r f g -> f x (r g f)) 
               (\ _ _ -> []) 
               xs 
               (:)
               ((:) . (*2))

测试:

> bar [1..9]
[1,4,3,8,5,12,7,16,9]