Мы можем получить и использовать Foldable
, чтобы сложить в специальный моноид для выполнения работы:
data Tree a = EmptyT
| NodeT a ( Tree a ) ( Tree a )
deriving (Show, Functor, Foldable)
data T a = T a -- tip
| N [[a]] -- node
| TN (a,[[a]]) -- tip <> node
| NN ([[a]],[[a]]) -- node <> node
deriving Show
instance Monoid (T a) where
mempty = N [] -- (tip <> node <> node) is what we actually want
mappend (T a) (N as) = TN (a,as) -- tip <> node
mappend (N as) (N bs) = NN (as,bs) -- node <> node
mappend (T a) (NN ([],[])) = N ([[a]]) -- tip <> (node <> node)
mappend (T a) (NN (as,bs)) = N (map (a:) as ++ map (a:) bs)
mappend (TN (a,[])) (N []) = N ([[a]]) -- (tip <> node) <> node
mappend (TN (a,as)) (N bs) = N (map (a:) as ++ map (a:) bs)
allPaths :: Tree a -> [[a]]
allPaths (foldMap T -> N ps) = ps
В определении функции allPaths
используется ViewPatterns
,Тестирование,
> allPaths $ NodeT 1 (NodeT 2 (NodeT 3 EmptyT EmptyT) EmptyT)
(NodeT 5 EmptyT EmptyT)
[[1,2,3],[1,5]]
> allPaths $ NodeT 1 (NodeT 2 (NodeT 3 EmptyT EmptyT) (NodeT 4 EmptyT EmptyT))
(NodeT 5 EmptyT EmptyT)
[[1,2,3],[1,2,4],[1,5]]
(tip <> node <> node)
- это то, что мы действительно хотим, но <>
является двоичным, и мы не знаем (и не должны полагаться на это, если бы мы это сделали) фактический порядок, в которомчасти будут объединены в единое целое по производному определению foldMap
,
foldMap T EmptyT == N []
foldMap T (NodeT a lt rt) == T a <> foldMap T lt <> foldMap T rt
-- but in what order?
Таким образом, мы «подделываем» его, задерживая фактическую комбинацию, пока все три части не станут доступны.
Или мы могли бы вообще отказаться от маршрута деривации, использовать приведенные выше законы в качестве определения пользовательского foldMap
с троичной комбинацией и в конечном итоге ... эквивалент рекурсивного кода в другом ответе- намного короче в целом, без утилитарных утилит однократных вспомогательных типов, которые должны быть спрятаны за стенками модулей, и самоочевидно неполными, в отличие от того, с чем мы здесь столкнулись.
Так что, возможно, это не так здорово.Я все равно выложу, как контрапункт.