我刚刚开始使用Haskell并想编写一个函数,给定一个列表,返回一个列表,其中每个第二个元素都被加倍。
到目前为止,我已经想出了这个:
double_2nd :: [Int] -> [Int]
double_2nd [] = []
double_2nd (x:xs) = x : (2 * head xs) : double_2nd (tail xs)
哪个有效,但我想知道你们怎么会写这个功能。是否有更常见/更好的方式或看起来是对的?
答案 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)
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]