Одним из основных аспектов Haskell является то, что концептуально функция всегда принимает один аргумент. Действительно, например, взять функцию (+)
:
(+) :: Int -> Int -> Int
(технически это (+) :: Num a => a -> a -> a
, но давайте не усложнять).
Теперь вы можете утверждать, что (+)
принимает два аргумента, но концептуально он принимает один аргумент. Действительно: подпись фактически
(+) :: Int -> (Int -> Int)
Таким образом, вы кормить его один целое и теперь она возвращает функцию, например:
(+) 5 :: Int -> Int
Так у вас есть, давая ему 5
, построенный функция, которая добавит 5 к заданному операнду (снова функция, которая принимает один аргумент).
Применяя это к вашему вопросу, подпись all'
фактически:
all' :: (a -> Bool) -> ([a] -> Bool)
Так что, если вы применяете all'
с одним аргументом, он возвращает функцию, которая отображает список [a]
к Bool
. Скажем, ради аргумента, что мы устанавливаем p
в \_ -> True
, то мы возвращаем:
foldr (&&) True . map (\_ -> True) :: [a] -> Bool
так действительно является функцией, которая принимает список [a]
и отображает его на Bool
. В следующей фазе вы применяете список к , который (возврат) функции.
Другими словами, функциональное программирование можно рассматривать как длинную цепочку, специализирующую функцию дальше и дальше, пока она не будет полностью заземлена и не будет оценена.
Haskell предоставляет только это элегантным способом, так что вам не нужно думать о функциях, генерирующих функции. Но концептуально это происходит все время.Учитывая, вы хотите реализовать функцию f :: a -> b -> c
, вы можете сделать это, как:
f x y = g (x+1) y
(с g :: a -> b -> c
), но вы можете также принять решение оставить параметр вне, и определить его как:
поскольку g (x+1)
вернет функцию, которая может применяться с y
в конце концов.
Запись 'f x = g x. h x' то же, что и запись 'f x y = g x (h x y)', по определению оператора композиции '.'. Первый стиль называется «бессмысленным стилем» (или, в шутку, без точечного стиля). – chi
Одно слово: каррирование. – chepner