开发者

How many arguments takes the foldr function of Haskell?

I am new to Haskell and I am reading the book "Real World Haskell". In the Chapter 4 of the book the author asks as an exercise to rewrite the groupBy function using fold. One of the readers of the book (Octavian Voicu ) gave the following solution:


theCoolGroupBy :: (a -> a -> Bool) -> [a] -> [[a]]
theCoolGroupBy eq xs = tail $ foldr step (\_ -> [[]]) xs $ (\_ -> False)
                       where step x acc = \p -> if p x then rest p else []:re开发者_开发百科st (eq x)
                                          where rest q = let y:ys = acc q in (x:y):ys

My question is simple: I know that foldr takes 3 arguments: a function, an initial value and a list. But in the second line of the code foldr takes 4 arguments. Why this happens? Thank you.


In this situation, I think it is best to look at the type signature of foldr:

foldr :: (a -> b -> b) -> b -> [a] -> b

and to match that to the expression we have (with added parenthesis for clarity):

(foldr step (\_ -> [[]]) xs) (\_ -> False)

The second argument of foldr is the same type as its result. In this case the second argument is a function. In this case, this means that the foldr expression with 3 arguments will be a function.

What you see to be the 4th argument of the foldr function could also be thought of as the 1st argument of the foldr result!


All functions in Haskell take just one argument. When we have a function with type a -> b -> c, it is just a shorter way to write a -> (b -> c), i.e. a function, which takes one argument and produces a function which takes another argument. See Currying for more information.

In this case, see the @sepp2k's answer. foldr produces a function and it needs another ("the 4th") argument.


In this case foldr is used to build up a function. (\_ -> False) is the argument to that function.


Scott's answer is correct, the result of the foldr is a function, so this is why it seems that foldr takes 4 arguments. The foldr functions does take 3 arguments (function, base, list):

*Main> :type foldr
foldr :: (a -> b -> b) -> b -> [a] -> b

I'll just give here an example that is less complex:

inc :: Int -> (Int -> Int)
inc v = \x -> x + v

test = inc 2 40  -- output of test is 42

In the above code, inc takes one argument, v, and returns a function that increments its argument by v.

As we can see below, the return type of inc 2 is a function, so its argument can simply be added at the end:

*Main> :type inc
inc :: Int -> Int -> Int
*Main> :type inc 2
inc 2 :: Int -> Int
*Main> :type inc 2 40                                                        
inc 2 40 :: Int

Parentheses could be used to emphasize that the return value is a function, but functionally it is identical to the above code:

*Main> (inc 2) 40
42

PS: I'm the author of the original comment :)

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜