使用takewhile和iterate的惯用haskell

使用takewhile和iterate的惯用haskell,haskell,Haskell,我试图通过在线课程学习Haskell。在其中一个练习中,学生应重新编写函数: fun1 :: [Integer] -> Integer fun1 [] = 1 fun1 (x:xs) | even x = (x - 2) * fun1 xs | otherwise = fun1 xs 变成更“地道”的哈斯克尔。我将函数重写为 fun1 :: [Integer] -> Integer fun1 xs = let spl = partition even xs in f

我试图通过在线课程学习Haskell。在其中一个练习中,学生应重新编写函数:

fun1 :: [Integer] -> Integer
fun1 [] = 1
fun1 (x:xs)
  | even x = (x - 2) * fun1 xs
  | otherwise = fun1 xs
变成更“地道”的哈斯克尔。我将函数重写为

fun1 :: [Integer] -> Integer
fun1 xs =
  let spl = partition even xs
  in foldl (*) 1 ((map (subtract 2) (fst spl)) ++ snd spl)

这似乎。。。莉西。它几乎把一个字一个字地翻译成了我用clojure写它的方式。在赋值中,它给出了使用序言中的
takeWhile
iterate
重写函数的提示。虽然我表面上了解这些函数的作用,但我并不清楚如何重写该函数以使用它们。如何使用
takeWhile
iterate
重写此代码?

这实际上与
takeWhile
没有多大关系。对于给定列表中的每个偶数
x
,只需在此计算
x-2
的乘积。事实上:

fun1 :: [Integer] -> Integer
fun1 [] = 1 -- the product of an empty list is 1
fun1 (x:xs)
  -- if the number is even, we multiply (x-2) with the remaining part
  | even x = (x - 2) * fun1 xs
  -- if the number is odd, we ignore x and return the fun1 of the tail
  | otherwise = fun1 xs
所以我们可以这样写:

fun1 :: Integral i => [i] -> i
fun1 = product . map (subtract 2) . filter even
如果您不能使用
产品
,您可以使用-就像您在问题中所做的那样-使用:

fun1 :: Integral i => [i] -> i
fun1 = foldl (*) 1 . map (subtract 2) . filter even
这就是我们所说的无点版本:
fun1
的头部或任何lambda表达式中都没有参数。因此,我们不是从价值的角度思考问题,而是更多地从功能的角度思考问题

对于列表
[1,3,4]
,这将生成:

Prelude> (foldl (*) 1 . map (subtract 2) . filter even) [1,3,4]
2

使用
takeWhile
iterate
(至少在我看来)编写此函数没有明显、自然的方法。如果有什么区别的话,这是一个心理体操的练习。还要注意的是,您的第二个函数与第一个函数不同——第一个函数忽略奇数值,而第二个函数则不同。@user2407038是的,我误解了这个练习的性质,因此我使用了分区和连接。