Давайте посмотрим на ваши определениях сумма
sum :: (Num a) => [a] -> a
sum xs = foldl (\acc x -> acc + x) 0 xs
Давайте также взглянем на подпись foldl в:
foldl :: (a -> b -> a) -> a -> [b] -> a
Хмм, хорошо, что нам нужно кормить складки, чтобы получить значение на самом конце (->a
)?
Для этого нужна функция в карри (a->b->a)
. Все, хотя и неточно, для краткости, мы скажем его функцию, которая принимает два аргумента (но вы и я знаем, что на самом деле он принимает один аргумент и возвращает другую функцию, которая принимает один аргумент).
Нужно значение типа a
. Обратите внимание, что наша каррическая функция с шага 1. принимает что-то типа a
и возвращает что-то типа a
. Интересно ... hmmm ...
Нужен список типов b
.Обратите внимание, что наша каррическая функция с шага 1 принимает, а также что-то типа a
, что-то типа b
.
Итак, даем ли мы это, что он хочет?
Мы даем (\acc x -> acc + x)
. Это анонимная функция, или lambda, что принимает два аргумента (помните, что это было на самом деле), acc
и x
, и возвращает их сумму.
Мы даем ему 0
в качестве отправного значения
Мы даем это xs
как список сброситься.
Ok dokie. Итак, давайте просто позволим foldl работать с магией Haskell. Давайте представим, что мы называли sum [1,2,3]
foldl
вызывает нашу функцию (\acc x -> acc + x)
, используя 0
для acc
и первое значение xs
, 1
.
0 + 1
Этот результат делает не откладываются в сторону acc
или x
, так как они только аргументы в нашей маленькой лямбда-функции. foldl
будет использовать это значение (см. Ответ SanSS для конкретной реализации).
Помните, что результатом нашей лямбда-функции является тот же тип, что и первый параметр? foldl может использовать эту предыдущую сумму и передать ее обратно в функцию лямбда, а также второй элемент.
(0 + 1) + 2
И снова, пока он сделал это для всех элементов:
((0 + 1) + 2) + 3
6
Как было отмечено Dan, это то же самое, если бы вы сделали:
sum xs = foldl (+) 0 xs
Вы можете проще сказать с помощью этой функции, что мы не просто «устанавливаем» какую-то переменную и добавляем на нее.
Надеюсь, это поможет.
Side Примечание: Для вашего определения суммы, вы не должны явно указать, что sum
xs
принимает. Вы можете оставить его как:
sum = foldl (\acc x -> acc + x) 0
Это использует выделки, потому что если мы обеспечиваем foldl только первые два аргумента - каррированная функцию, как (a->b->a)
и значение типа a
- то, что мы получаем ?
[b] -> a
Функция, которая принимает список типов b
и возвращает значение типа a
! Это называется pointfree style. Просто подумать :-)
В чем вопрос? – delnan