Ho pensato a come generalizzare scanl
in ADT arbitrari. L'approccio Prelude consiste nel trattare tutto come un elenco (ad esempio, Foldable
) e applicare lo scanl
sulla vista piatta della struttura. Invece, tendo a pensare a scanl
come a un'operazione che passa uno stato da ciascun nodo dell'albero ai suoi figli, mentre applica un op monoidale mentre scende dalla radice alle foglie. Così, per esempio, su Data.Tree
, abbiamo:Si tratta di una generalizzazione significativa di `scan`s per ADT arbitrari?
scan :: (b -> a -> b) -> b -> Tree a -> Tree b
scan fn init (Node element children)
= Node (fn init element)
$ map (treeScan fn (fn init element)) children
In modo che, ad esempio:
main = do
prettyPrint $ scan (+) 0 $
Node 1 [
Node 1 [
Node 1 [],
Node 1 []],
Node 1 [
Node 1 [],
Node 1 []]]
Risultati in:
1
|
+- 2
| |
| +- 3
| |
| `- 3
|
`- 2
|
+- 3
|
`- 3
Che è lo stesso che si applica scanl
attraverso ogni percorso dell'albero in modo indipendente, preservando la struttura originale.
La domanda è piuttosto semplice: si tratta di una generalizzazione significativa? Ad esempio, è comunemente usato, con una spiegazione categorica e forse con un nome diverso?
Bene, c'è ['scanl1Of'] (http://hackage.haskell.org/package/lens-4.13/docs/Control-Lens-Traversal.html#v:scanl1Of). Con un appropriato 'Traversal' questo potrebbe fare il trucco. – leftaroundabout
Non sono sicuro che questo 'scanl' esteso debba passare lo stesso' init' a tutti i bambini, come fatto sopra, o incatenarli come fa 'fold'. – chi
** scan ** di 'chi ** 'è' scan :: Traversable f => (b -> a -> b) -> b -> f a -> f b; scan f z a = evalState (traversa (\ x -> modifica (flip f x) >> get) a) z'. – user3237465