One of the fundamental aspects of Haskell is that conceptually a function always takes one argument. Indeed take for instance the function (+)
:
(+) :: Int -> Int -> Int
(technically it is (+) :: Num a => a -> a -> a
, but let us keep things simple).
Now you can argue that (+)
takes two arguments, but conceptually it takes one argument. Indeed: the signature is in fact
(+) :: Int -> (Int -> Int)
So you feed it one integer and now it returns a function, for instance:
(+) 5 :: Int -> Int
So you have, by giving it a 5
, constructed a function that will add 5 to a given operand (again a function that takes one argument).
Now applying this to your question, the signature of all'
is in fact:
all' :: (a -> Bool) -> ([a] -> Bool)
So if you apply all'
with one argument, it returns a function that maps a list [a]
to a Bool
. Say for the sake of argument that we set p
to \_ -> True
, then we return:
foldr (&&) True . map (\_ -> True) :: [a] -> Bool
so indeed a function that takes a list [a]
and maps it on a Bool
. In a next phase you apply a list to that (returning) function.
In other words, functional programming can be seen as a long chain of specializing a function further and further until it is fully grounded and can be evaluated.
Haskell only provides this in an elegant way such that you do not have to think about functions generating functions. But conceptually, this happens all the time. Given you want to implement a function f :: a -> b -> c
, you can do this like:
f x y = g (x+1) y
(with g :: a -> b -> c
), but you can also decide to leave a parameter out, and define it as:
f x = g (x+1)
since g (x+1)
will return a function that can apply with the y
eventually.