Я знаю, как работает foldr на Leaf, но я не знаю, как работает foldr на Node. Что такое параметр \ x z ', если у нас уже есть f и z в качестве параметра. предположим, у нас есть

tree = Node [Leaf 1, Leaf 2, Node [Leaf 1, Leaf 3]]

Как работает этот код

foldr (+) 0 tree
data RoseTree a =  Leaf a | Node [RoseTree a] 
instance Foldable RoseTree where 
    foldr f z (Leaf x) = f x z
    foldr f z (Node ns) = 
        foldr (\x z' -> foldr f z' x) z ns 
3
Y.Gao 28 Май 2019 в 06:37

2 ответа

Лучший ответ

Мы можем обсудить реализацию с вашими данными примера:

foldr (+) 0 (Node [Leaf 1, Leaf 2, Node [Leaf 1, Leaf 3]])

Таким образом, здесь у нас есть Node, поэтому мы берем второе предложение и заменяем его следующим:

foldr (\x z' -> foldr (+) z' x) 0 [Leaf 1, Leaf 2, Node [Leaf 1, Leaf 3]]

Таким образом, внешний foldr работает с этим списком, что означает, что документация:

foldr f z [x1, x2, ..., xn] == x1 `f` (x2 `f` ... (xn `f` z)...)

Таким образом, это означает, что вышеуказанное foldr заменено на:

foldr (+) (foldr (+) (foldr (+) 0 (Node [Leaf 1, Leaf 3])) (Leaf 2)) (Leaf 1)

Итак, внешняя функция теперь foldr (+) (...) (Leaf 1), это первое предложение нашего foldr определения, так что оно равно:

(+) 1 (foldr (+) (foldr (+) 0 (Node [Leaf 1, Leaf 3])) (Leaf 2))

Затем мы можем оценить выражение foldr (+) (...) (Leaf 2), которое обрабатывается таким же образом:

(+) 1 ((+) 2 (foldr (+) 0 (Node [Leaf 1, Leaf 3])))

Или менее многословный:

1 + 2 + foldr (+) 0 (Node [Leaf 1, Leaf 3])

Затем, наконец, у нас снова есть foldr (+) 0, который работает с Node, что, таким образом, снова приводит к оценке, как обсуждалось выше:

1 + 2 + foldr (+) (foldr (+) 0 (Leaf 3)) (Leaf 1)

Таким образом, мы снова можем оценить внешний foldr (+):

1 + 2 + (+) 1 (foldr (+) 0 (Leaf 3))

И внутренний foldr (+) для:

1 + 2 + (+) 1 ((+) 3 0)

Или менее многословный:

1 + 2 + 1 + 3 + 0

Что эквивалентно:

7

Которая является суммой узлов в Leaf с.

Важно отметить, что внешняя foldr (обозначаемая здесь курсив ) не является той же foldr функцией, что и внутренняя foldr (здесь обозначено boldface ) в реализации: внешний работает со списком в качестве функтора, тогда как внутренний - это тот, который мы определяем в {{X3 } } :

instance Foldable RoseTree where 
    foldr f z (Leaf x) = f x z
    foldr f z (Node ns) = foldr (\x z' -> foldr f z' x) z ns

Таким образом, если мы выполним foldr для Tree с функцией f и начальным значением z, мы заменим все листы на f x z, (так для foldr (+) 0 это (+) x 0 или x + 0).

Node s приведет к свертыванию значений вместе, где результат сгиба элементов хвоста используется в качестве начального значения сгиба с элементом head.

4
Willem Van Onsem 28 Май 2019 в 10:22

Определение foldr для Node вызовов foldr в списке RoseTree. Затем внутри этого foldr он вызывает foldr для каждого поддерева, используя текущий аккумулятор в качестве начального параметра.

По сути, даже если она выглядит как функция, вызывающая foldr дважды, она каждый раз вызывает ее для разных типов, и поэтому только один из них является рекурсивным. Другой - foldr, определенный для [a].

6
Izaak Weiss 28 Май 2019 в 04:37