2011-01-21 3 views
1
sum :: (Num a) => [a] -> a 
sum xs = foldl (\acc x -> acc + x) 0 xs 

foldl - это складки списка вверх с левой стороны. Итак, сначала мы получим acc=0 и поместим список xs в x, затем выполним функцию ->acc+x. После вычисления получим новый acc, который равен acc+x. Но почему? Я думаю, что этот результат acc+x - это новое значение x на основе функции x->acc+x.объясните, как использовать эту функцию foldl

+0

В чем вопрос? – delnan

ответ

3

Давайте посмотрим на ваши определениях сумма

sum :: (Num a) => [a] -> a 
sum xs = foldl (\acc x -> acc + x) 0 xs 

Давайте также взглянем на подпись foldl в:

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

Хмм, хорошо, что нам нужно кормить складки, чтобы получить значение на самом конце (->a)?

  1. Для этого нужна функция в карри (a->b->a). Все, хотя и неточно, для краткости, мы скажем его функцию, которая принимает два аргумента (но вы и я знаем, что на самом деле он принимает один аргумент и возвращает другую функцию, которая принимает один аргумент).

  2. Нужно значение типа a. Обратите внимание, что наша каррическая функция с шага 1. принимает что-то типа a и возвращает что-то типа a. Интересно ... hmmm ...

  3. Нужен список типов b.Обратите внимание, что наша каррическая функция с шага 1 принимает, а также что-то типа a, что-то типа b.

Итак, даем ли мы это, что он хочет?

  1. Мы даем (\acc x -> acc + x). Это анонимная функция, или lambda, что принимает два аргумента (помните, что это было на самом деле), acc и x, и возвращает их сумму.

  2. Мы даем ему 0 в качестве отправного значения

  3. Мы даем это 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 Примечание: Для вашего определения суммы, вы не должны явно указать, что sumxs принимает. Вы можете оставить его как:

sum = foldl (\acc x -> acc + x) 0

Это использует выделки, потому что если мы обеспечиваем foldl только первые два аргумента - каррированная функцию, как (a->b->a) и значение типа a - то, что мы получаем ?

[b] -> a

Функция, которая принимает список типов b и возвращает значение типа a! Это называется pointfree style. Просто подумать :-)

+0

Я смутился об этой лямбда-функции. Теперь, я понимаю. Спасибо !!!! – CathyLu

3

Вы должны смотреть на определение foldl:

foldl f z []  = z 
foldl f z (x:xs) = foldl f (f z x) xs 

foldl recieves с несильно, который принимает 2 аргумента, значение («стоимость стартера» или аккумулятора) и список. В случае, если список пуст, он возвращает текущий расчет. Если случай не пуст, он вызывает рекурсивно с той же функцией, что и функция, аккумулятор является результатом вызова функции с использованием аккумулятора в качестве первого аргумента и первого элемента списка в качестве второго аргумента и хвоста списка используется как список для рекурсивного вызова.

Таким образом, функция лямбда, используемая в сумме, становится совершенно понятной, она принимает в качестве первого аргумента и элемент списка как второй аргумент и возвращает сумму обоих.

Результат вызовов для:

sum [1,2,3] = ((0 + 1) + 2) + 3 = 6 
1

Вашего вопроса, это звучит, как вы не понимаете, как функция лямбды (\acc x -> acc + x) здесь работает.

Функция не x->acc+x, но acc x->acc + x. На самом деле, вы могли бы переписать «сумму» уравнение в виде

sum xs = foldl (+) 0 xs 

С (\acc x -> acc + x) таким же, как (+)

Я предлагаю вам (заново) прочитать http://learnyouahaskell.com/higher-order-functions#lambdas

Смежные вопросы