Мы можем восстановить линейные сгибы, проходящие через аккумулятор, из сгибов в форме дерева, следующих за типом данных, сложив в endofunctions , например:
data Tree a = Leaf | Node (Tree a) a (Tree a) deriving (Eq, Show)
-- foldTree :: (b -> a -> b -> b) -> b -> Tree a -> b
foldTreeR :: (a -> r -> r) -> r -> Tree a -> r
foldTreeR cons z t = foldTree g id t z -- b ~ r -> r
where
g lt a rt = lt . cons a . rt
И левый сгиб:
foldTreeL :: (acc -> a -> acc) -> acc -> Tree a -> acc
foldTreeL conj z t = foldTree g id t z -- b ~ acc -> acc
where
g lt a rt = rt . flip conj a . lt
Более подробные объяснения:
И cons a
, и flip conj a
имеют тип r -> r
(или acc -> acc
, что совпадает).Это тип функций с одинаковым типом аргумента и результата.
Такие функции известны как эндофункции, endo , указывающие на одинаковость их домена и кодомена (типы справа и слева от стрелки).Как таковые, они составляют легко: могут участвовать в операции (.)
, то есть в композиции функций, в результате чего композиция имеет тот же тип, что и типы операндов:
(.) :: (b -> c) -> (a -> b) -> (a -> c)
(f . g) x = f (g x)
-- and for endofunctions,
-- ((f :: r -> r) . (g :: r -> r)) :: r -> r
Длядерево с обходом в порядке [a,b,c,...,n]
, правая складка превращает это дерево в композицию
(cons a . cons b . cons c . ..... . cons n) z
-- which is the same as
-- cons a (cons b (cons c ... (cons n z) ... ))
, а левая складка превращает его в
(conj' n . ..... . conj' c . conj' b . conj' a) z
, где
conj' a acc = flip conj a acc = conj acc a -- by definition of `flip`
-- so the above composition chain is the same as
-- conj (... (conj (conj (conj z a) b) c) ...) n
с некоторыми id
s, разбросанными по этой цепочке, каждый Leaf
превращается в id
, не влияя на всю цепочку, потому что
(id . f) x = id (f x) = f x = f (id x) = (f . id) x
так
id . f = f = f . id
т.е. id
, служащий нулевым элементом по отношению к операции компоновки функции, точно так же, как 0
делает с операцией +
(это, кстати, упоминается как 'моноид' , образованный .
и id
или 0
и +
).
Вот как мы создали бы этот упорядоченный обходсписок для дерева:
inorder :: Tree a -> [a]
inorder t = foldTree g [] t
where
g lt a rt = lt ++ [a] ++ rt
Таким образом, список [a,b,...,n]
фактически создается как
[] ++ [a] ++ [] ++ [b] ++ [] ++ ... ++ [n] ++ []
и правый сгиб oЕсли это дерево будет создано как
(id . cons a . id . cons b . id . .... . cons n . id) z