我对Haskell很新,并且在这里使用函数进行了一些努力。前提很简单:运行一个列表,并将每个彼此相邻的3个项目与另一个函数相结合,并返回一个包含结果的列表。问题是以一种很好的方式做到这一点。
以下是我所得到的:
foo :: [Int] -> [Int]
foo xs
| length xs < 3 = []
| otherwise = n : foo (tail xs)
where n = calc (xs!!0) (xs!!1) (xs!!2)
-- This function is actually significantly more complicated.
calc :: Int -> Int -> Int -> Int
calc x y z = x + y - (z * 2)
-- And we can use it like this:
foo [1,2,3] -- [-3]
foo [1,2,3,4] -- [-3,-3]
foo [1,1,5,3,3] -- [-8,0,2]
我不喜欢的是第5行,其中包含所有!!
个。感觉就像我错误地思考它,并且应该有更好的方法来做到这一点。我想做像
foo (x:y:z:xs)
-- ...
但是当列表少于三个项目时,这将失败。那么,当列表中的项目较少时,我必须声明其他模式吗?
此外,如果已经有一个函数执行了foo
所做的事情(可能有,似乎所有东西都有),那么我并不是真的对此感兴趣。我试图了解Haskell的做事方式,而不仅仅是扩展我的功能重复。
编辑:在JS中,我会做n = calc.apply(null, take(3, xs))
之类的事情。我想知道Haskell是否有类似apply
的东西,它接受一个数组并将它作为参数应用于函数。
编辑2 - 解决方案:(根据以下评论)
foo (x:y:z:xs) = calc x y z : foo (y:z:xs)
foo _ = []
最后的模式匹配是一个全能的,所以如果第一个&#34;失败&#34;它将落空并返回一个空列表。
答案 0 :(得分:3)
好吧,foo (x:y:z:xs)
加上“太短的条款”肯定不是一个糟糕的解决方案。另一个是
foo xs = case splitAt 3 xs of
([x,y,z],xs') -> calc x y z : foo (y:z:xs')
_ -> []
或者,也许是最好的,
import Data.List (tails)
foo xs = [ calc x y z | (x:y:z:_) <- tails xs ]