我试图通过the CIS 194 course at the University of Pennsylvania课程在线学习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)
似乎...... lispy。它将角色的几乎字符翻译成我在clojure中编写它的方式。在赋值中,它提供了使用Prelude中的takeWhile
和iterate
来重写函数的提示。虽然我从表面上理解这些函数的作用,但对我来说,如何重写该函数以使用它们并不是很明显。如何使用takeWhile
和iterate
?
答案 0 :(得分:3)
这实际上与takeWhile
没什么关系。您只需针对给定列表中的每个偶数号x-2
计算x
的产品。事实上:
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
如果您无法使用product
,您可以像使用问题一样使用:
fun1 :: Integral i => [i] -> i
fun1 = foldl (*) 1 . map (subtract 2) . filter even
这就是我们所说的 pointfree 版本:fun1
或任何lambda表达式的头部都没有参数。因此,我们不考虑价值观,而是考虑功能。
对于列表[1,3,4]
,这会生成:
Prelude> (foldl (*) 1 . map (subtract 2) . filter even) [1,3,4]
2