Haskell recursive function example with foldr

a function that takes one arguments and returns a Boolean value. Since the > operator is actually an infix function, the first argument in the example above seems the result of a partial application to the > function – is this correct?

yes: (>10) is short for \x -> x > 10, just as (10>) would be short for \x -> 10 > x.

an unspecified value of the same type expected as the missing argument to the function provided as the first argument

first of all, it's not a missing argument: by omitting an argument, you obtain a function value. however, the type of the 2nd argument does indeed match the argument of the function >10, just as it matches the type of the elements of the list [10,20,30,40] (which is better reasoning).

a list of values of the aforementioned type

yes.

But the actual function firstThat seems to be defined differently from its type declaration, with just one argument. Since foldr normally takes three arguments I gathered there is some kind of partial application happening. The lambda expression provided as an argument to foldr seem to be missing its arguments too.

that's because given e.g. foo x y z = x * y * z, these 2 lines are equivalent:

bar x     = foo x
bar x y z = foo x y z

— that's because of a concept called currying. Currying is also the reason why function type signatures are not (a, b) -> c but instead a -> b -> c, which in turn is equivalent to a -> (b -> c) because of the right associativity of the -> type operator.

Therefore, these two lines are equivalent:

firstThat f     = foldr (\x acc -> if f x then x else acc)
firstThat f x y = foldr (\x acc -> if f x then x else acc) x y

Note: that you can also use Data.List.find combined with Data.Maybe.fromMaybe:

λ> fromMaybe 2000 $ find (>10) [10, 20, 30]
20
λ> fromMaybe 2000 $ find (>10) [1, 2, 3]
2000

See also:

  • https://en.wikipedia.org/wiki/Currying.
  • https://www.fpcomplete.com/user/EFulmer/currying-and-partial-application
  • http://learnyouahaskell.com/higher-order-functions

But the actual function firstThat seems to be defined differently from its type declaration, with just one argument. Since foldr normally takes three arguments I gathered there is some kind of partial application happening.

You are right. However, there is a nicer way of putting it than talking about "missing arguments" -- one that doesn't lead you into asking where they have gone. Here are two ways in which the arguments are not missing.

Firstly, consider this function:

add :: Num a => a -> a -> a
add x y = x + y

As you may know, we can also define it like this:

add :: Num a => a -> a -> a
add = (+)

That works because Haskell functions are values like any other. We can simply define a value, add, as being equal to another value, (+), which just happens to be a function. There is no special syntax required to declare a function. The upshot is that writing arguments explicitly is (almost) never necessary; the main reason why we do so because it often makes code more readable (for instance, I could define firstThat without writing the f parameter explicitly, but I won't do so because the result is rather hideous).

Secondly, whenever you see a function type with three arguments...

firstThat :: (a -> Bool) -> a -> [a] -> a

... you can also read it like this...

firstThat :: (a -> Bool) -> (a -> [a] -> a)

... that is, a function of one argument that produces a function of two arguments. That works for all functions of more than one argument. The key takeaway is that, at heart, all Haskell functions take just one argument. That is why partial application works. So on seeing...

firstThat :: (a -> Bool) -> a -> [a] -> a
firstThat f = foldr (\x acc -> if f x then x else acc)

... you can accurately say that you have written explicitly all parameters that firstThat takes -- that is, only one :)


The lambda expression provided as an argument to foldr seem to be missing its arguments too.

Not really. foldr (when restricted to lists) is...

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

... and so the function passed to it takes two arguments (feel free to add air quotes around "two", given the discussion above). The lambda was written as...

\x acc -> if f x then x else acc

... with two explicit arguments, x and acc.