简体   繁体   English

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

[英]Why does n-reduction not apply to filter even in the following example?

I am following 'Learn Haskell Fast and Hard' and I was able to follow most of it, but I have two questions for the following code sample. 我正在关注“快速学习Hardkell”,并且能够遵循其中的大多数要求,但是对于以下代码示例,我有两个问题。

  1. In the first function, why don't I need l but in the second version I do need l ? 在第一个函数中,为什么我不需要l但是在第二个函数中,我确实需要l
  2. In evenSum1 , when the function is called recursively will filter be called on the list again and again or will filter be called only once on the first call? evenSum1 ,当函数被调用递归会filter被列入名单一再呼吁或将filter被第一次调用只能调用一次?

.

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

You can actually drop of the l in the second example too, but you need to switch to what is called point free notation and use the function composition operator (.) : 您实际上也可以在第二个示例中删除l ,但是您需要切换到所谓的无点表示法,并使用函数组合运算符(.)

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

And in evenSum1 , the filter even function will only be called once. 并且在evenSum1filter even函数将仅被调用一次。 What happens is that filter even runs out the list passed in, then the output of that is passed to mysum 0 . 发生的情况是, filter even用完了传入的列表,然后将其输出传递到mysum 0


A quick primer on point free notation 无点符号快速入门

Say you have a function add : 假设您有一个add函数:

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

And then you want to make a function add5 that always adds 5 to an Int . 然后,您想制作一个函数add5 ,它总是将5加到Int You could do it as 你可以这样做

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

But since functions are first class objects in Haskell and we can partially apply a function, this is equivalent to saying 但是由于函数是Haskell中的第一类对象,并且我们可以部分应用函数,所以这相当于说

add5 :: Int -> Int
add5 = add 5

Another way to look at it is to add some optional parentheses to the type signature of add : 另一种查看方式是在add的类型签名中add一些可选的括号:

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

Written like this, we can say that add is a function that accepts a single Int argument and returns a new function of Int -> Int . 这样写,我们可以说add是一个接受单个Int参数并返回Int -> Int新函数的函数。 So if we give add a single Int , we get a new function back. 因此,如果我们给add一个Int ,我们将返回一个新函数。 This is also what lets us write expressions like 这也是让我们编写如下表达式的原因

filter even list

Instead of 代替

filter (\x -> even x) list

A good rule of thumb for point-free notation is that variables can be dropped off the end turning the last $ into a . 无点表示法的一个很好的经验法则是,变量可以从末尾删除,从而将最后的$变成a . :

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

This doesn't always work with multi-argument functions: 这不适用于多参数函数:

f x y = h $ g x y

Is not the same as 与...不同

f = h . g

Because h . g 因为h . g h . g won't type check. h . g不会键入检查。 This is because of implicit parentheses: 这是由于隐式括号引起的:

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

And now there's parentheses in the way from being able to drop the x argument. 现在,可以删除x参数的方式带有括号。

Also, keep in mind that fxy = h (gxy) is equivalent to fxy = h $ gxy , so you can usually turn the outermost parentheses into a $ instead, potentially letting you eta-reduce and change the $ to a . 另外,请记住, fxy = h (gxy)等同于fxy = h $ gxy ,因此通常可以将最外面的括号改为$ ,这可能使您将eta减少并把$更改为a . . If all this seems confusing, you can also grab the pointfree package off hackage, which contains a command line tool for automatically performing eta-reductions for you. 如果这一切看起来令人困惑,您还可以从hackage那里获取pointpoint软件包,该软件包包含一个命令行工具,可以自动为您执行eta减少操作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM