Как параметр аккумулятора отправляется в функцию? - PullRequest
0 голосов
/ 24 ноября 2018

В следующем коде я не могу понять, как отправляются параметры аккумулятора.

meanFold :: [Double] -> Double
meanFold l = (foldr op unit l) 0 0
    where
        unit :: Double -> Double -> Double
        unit n sum = sum / n
        op :: Double -> (Double ->Double ->Double) -> (Double -> Double -> Double)
        (x `op` y ) n sum = y (n+1) (sum +x)

Я понимаю, что foldr сначала применяет оператор op для последнего элемента в списке l иединица, которую я выбрал (которая будет функцией «единица измерения»).Но как параметры-накопители MeanFold отправляются в единичную функцию, так что сумма и n изначально равны 0?

Ответы [ 2 ]

0 голосов
/ 24 ноября 2018

Я понимаю, что foldr сначала применяет оператор op для последнего элемента в списке

Я не совсем уверен, что вы понимаете и этот бит.Сначала давайте рассмотрим тип foldr (специализированный для списков) и его определение.

foldr :: (a -> b -> b) -> b -> [a] -> b
foldr f e []     = e 
foldr f e (x:xs) = f x (foldr f xs)

* В данном случае a равно Double, а b равно Double -> Double -> Double.Первое, что вы знаете, это Double, потому что вы складываете список пар.Последний тип unit, который вы возвращаете в пустом регистре.

Итак, ваш foldr вычисляет функцию типа Double -> Double -> Double из списка значений типа double.В пустом случае вы просто возвращаете функцию

unit n sum = sum / n

, которая является функцией, которая делит свой второй аргумент на первый.То есть (/) но его аргументы поменялись местами.На каждом этапе сгиба вы модифицируете эту двоичную функцию, используя элемент списка.Вы изменяете его с помощью op

op :: Double -> (Double ->Double ->Double) -> (Double -> Double -> Double)
(x `op` y ) n sum = y (n+1) (sum +x)

Мне очень не нравится буква y, так как она выглядит как двойная.Давайте перепишем это как h.И давайте абстрагируемся также над n и sum, используя лямбду, чтобы было легче понять, что происходит.

op :: Double -> (Double ->Double ->Double) -> (Double -> Double -> Double)
(x `op` h) = \n sum -> h (n+1) (sum +x)

Таким образом, учитывая двойное значение x из списка и двоичную функцию h, рассчитанную до настоящего времени (которая изначально равна unit), мы собираемся вычислить новую функцию,

\n sum -> h (n+1) (sum+x)

, которая аналогична предыдущей функции h, за исключением того, что она суммирует 1 с первым аргументом и x со вторым перед применением h.

Таким образом, в итоге для списка [x1, x2, x3], который сворачивается, вернется функция,

\n sum -> (x1+x2+x3+sum) / (1+1+1+n)

И когда вы примените это к двум полученным нулям,

  (\n sum -> (x1+x2+x3+sum) / (1+1+1+n)) 0 0 
= (x1+x2+x3+0) / (1+1+1+0)
= (x1+x2+x3) / (1+1+1)
0 голосов
/ 24 ноября 2018

foldr будет применять функцию все еще с начала до конца коллекции, а не в обратном порядке.

Определение foldr дает представление о том, как она работает.Ключевое отличие от foldl - порядок скобок.

Подробнее здесь

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...