История изменений
Исправление
Crocodoom,
(текущая версия)
:
Что такое по сути foldr? Это замена n-арных конструкторов данных на n-арные функции.
Тип foldr для твоего дерева (использую твои обозначения):
foldr :: (a -> b -> b) -> b -> RoseTree a -> b
f :: a -> b -> b
acc :: b
Твоё дерево выглядит как
RoseTree a = RoseTree a (RoseTree a : RoseTree a : RoseTree a : ... : RoseTree a : [])
RoseTree — это конструктор, остальные — имя типа. Можно запутаться, но что поделать.У нас три конструктора под замену: RoseTree, (:) и []. Заменять должны на подходящие по арности и типам функции. И в результате должен получиться тип b.
Очевидно, что конструктор RoseTree надо заменить на f. А вот дальше возникают сложности. Обозначим пока замену (:) как ?, а замену [] как ??
b = f a (RoseTree a ? RoseTree a ? RoseTree a ? ... ? RoseTree a ? ??)
Т.к. второй аргумент у f имеет тип b, значит ? должен возвращать тип b. И первым аргументом ? должен принимать тип RoseTree a. То есть
? :: RoseTree a -> c -> b
Тип c мы пока не знаем. Подумаем, на что мы можем заменить ??. Это нуль-арный конструктор, значит мы его должны заменить на какую-то константу. Константа у нас по сути одна, это acc.
Значит ?? = acc и ?? :: b. Отсюда моментально получаем, что c = b.
Значит
? :: RoseTree a -> b -> b
Только одна функция имеет такой тип, это flip (foldr f). Теперь мы готовы делать foldr:
b = f a (RoseTree a `flip (foldr f)` RoseTree a `flip (foldr f)` RoseTree a `flip (foldr f)` ... `flip (foldr f)` RoseTree a `flip (foldr f)` acc)
Осталось свернуть этот паровоз в скобках в обычный foldr (уже для списков! не для дерева), собственно и получаем
f x (foldr (flip (foldr f)) acc ts)
Исходная версия
Crocodoom,
:
Что такое по сути foldr? Это замена n-арных конструкторов данных на n-арные функции.
Тип foldr для твоего дерева (использую твои обозначения):
foldr :: (a -> b -> b) -> b -> RoseTree a -> b
f :: a -> b -> b
acc :: b
Твоё дерево выглядит как
RoseTree a = RoseTree a (RoseTree a : RoseTree a : RoseTree a : ... : RoseTree a : [])
У нас три конструктора под замену: RoseTree, (:) и []. Заменять должны на подходящие по арности и типам функции. И в результате должен получиться тип b.
Очевидно, что конструктор RoseTree надо заменить на f. А вот дальше возникают сложности. Обозначим пока замену (:) как ?, а замену [] как ??
b = f a (RoseTree a ? RoseTree a ? RoseTree a ? ... ? RoseTree a ? ??)
Т.к. второй аргумент у f имеет тип b, значит ? должен возвращать тип b. И первым аргументом ? должен принимать тип RoseTree a. То есть
? :: RoseTree a -> c -> b
Тип c мы пока не знаем. Подумаем, на что мы можем заменить ??. Это нуль-арный конструктор, значит мы его должны заменить на какую-то константу. Константа у нас по сути одна, это acc.
Значит ?? = acc и ?? :: b. Отсюда моментально получаем, что c = b.
Значит
? :: RoseTree a -> b -> b
Только одна функция имеет такой тип, это flip (foldr f). Теперь мы готовы делать foldr:
b = f a (RoseTree a `flip (foldr f)` RoseTree a `flip (foldr f)` RoseTree a `flip (foldr f)` ... `flip (foldr f)` RoseTree a `flip (foldr f)` acc)
Осталось свернуть этот паровоз в скобках в обычный foldr (уже для списков! не для дерева), собственно и получаем
f x (foldr (flip (foldr f)) acc ts)