为什么即使在以下示例中,n-reduction也不适用于滤波器?

时间:2014-09-12 20:37:22

标签: haskell

我关注'Learn Haskell Fast and Hard'并且我能够完成大部分内容,但我对以下代码示例有两个问题。

  1. 在第一个函数中,为什么我不需要l但在第二个版本中我需要l
  2. evenSum1中,当递归调用该函数时,会一次又一次地在列表中调用filter,或者在第一次调用时只调用filter一次吗?
  3. evenSum = accumSum 0 
        where 
            accumSum n [] = n
            accumSum n (x:xs) =
                            if even x
                                    then accumSum (n+x) xs
                                    else accumSum n xs
    
    evenSum1 l = mysum 0 (filter even l)
        where
            mysum n [] = n
            mysum n (x:xs) = mysum (n+x) xs
    

1 个答案:

答案 0 :(得分:6)

您实际上也可以删除第二个示例中的l,但您需要切换到所谓的point free notation并使用函数组合运算符(.)

evenSum1 = mysum 0 . filter even
    where
        mysum n [] = n
        mysum n (x:xs) = mysum (n + x) xs

evenSum1中,filter even函数只会被调用一次。会发生的事情是filter even用完了传入的列表,然后将其输出传递给mysum 0


无点符号的快速入门

假设您有一个功能add

add :: Int -> Int -> Int
add x y = x + y

然后你想创建一个总是为add5添加5的函数Int。你可以这样做

add5 :: Int -> Int
add5 y = add 5 y

但是由于函数是Haskell中的第一类对象,我们可以部分应用函数,这相当于说

add5 :: Int -> Int
add5 = add 5

另一种看待它的方法是在add的类型签名中添加一些可选括号:

add :: Int -> (Int -> Int)
add x y = x + y

这样写的,我们可以说add是一个接受单个Int参数的函数,并返回Int -> Int的新函数。因此,如果我们给add一个Int,我们就会得到一个新函数。这也是让我们编写像

这样的表达式的原因
filter even list

而不是

filter (\x -> even x) list

无点符号的一个好的经验法则是,变量可以从最后$转变为.

f x y = h x $ g y
f x   = h x . g

f x y z = h x $ g y $ j z
f x y   = h x $ g y . j

这并不总是适用于多参数函数:

f x y = h $ g x y

不一样
f = h . g

因为h . g无法进行类型检查。这是因为隐含的括号:

f x y = h $ (g x) y
f x   = h . (g x)

现在有一些括号可以放弃x参数。

此外,请注意f x y = h (g x y)等同于f x y = h $ g x y,因此您通常可以将最外面的括号转换为$,这可能会让您减少并更改{ {1}}到$。如果所有这些看起来令人困惑,您还可以抓取pointfree hackage包,其中包含一个命令行工具,可以自动为您执行eta-reduction。