Reputation: 765
I can easily get a Traversal
to items stored in leaves:
data Tree a = Br (Tree a) (Tree a) | Lf a
deriving (Data)
instance Plated (Tree a) where
makePrisms ''Tree
leaves :: Traversal' (Tree a) a
leaves = deep _Lf
But deep
can't keep going if I take something out of a branch. The best I can seem to achieve with data in branches is a Fold
:
data Tree a = Br a (Tree a) (Tree a) | Lf
deriving (Data)
instance Plated (Tree a) where
makePrisms ''Tree
branchData :: Fold (Tree a) a
branchData = cosmos._Br._1
It is obviously possible to manually construct a Traversal
because this Tree
can be made Traversable
:
instance Traversable Tree where
sequenceA Lf = pure Lf
sequenceA (Br x l r) = Br <$> x <*> sequenceA l <*> sequenceA r
Can Plated
do it for us automatically somehow?
Upvotes: 3
Views: 173
Reputation: 2570
I do not believe it is possible to do using Plated
, but it is trivial to do using template
from Data.Data.Lens
:
branchData :: Data a => Traversal' (Tree a) a
branchData = template
Template finds all elements of a type that can be accessed without going through the same type.
The closest thing to a traversal that I can get from Plated
(except for the cosmos
fold you mentioned) is transformM :: (Monad m, Plated a) => LensLike' m a a
. It can be used as a Setter
and can do some other stuff.
The reason that transformM needs a Monad (instead of an Applicative that would be required for a traversal) is that we need to update the children before updating the node, which means that ordering is needed. It is impossible to make a traversal that points at both a node and a child of that node.
Upvotes: 3