Problem:
Starred Nodes:
Requirement:
Starting from this tree,
Node
"Root"
[ Node
"Alpha"
[ Node "Beta*" -- A starred node
[ Node "Gamma" [], -- Unstarred child of a starred node
Node "Delta*" -- Starred child of another starred node
[ Node "Epsilon" [] ] -- Unstarred child of "Delta*"
],
Node "Zeta" [] -- Unstarred node
],
Node
"Theta"
[ Node "Iota" [],
Node "Kappa*" [] -- Starred node that does not descend from other starred nodes
]
]
I would like to produce:
Node
"Root"
[ Node
"Beta*" -- A starred node
[ Node "Delta*" -- Starred child of another starred node
[]
],
Node "Kappa*" [] -- Starred node that does not descend from other starred nodes
]
Here's one straightforward answer. The spec is a little unclear about what should happen if the root node has a star (a literal reading says Node "*" []
should result in Node "*" [Node "*" []]
, which doesn't seem right), so I've fudged it: we'll return the direct children of the new root rather than a single tree with those as direct children. We're doing a recursion with two possible states: either we're the child of a starred node or not. If we're not under a starred node, we return the new direct children of the root. If we're under a starred node, we return the children of the parent and the children of the new root separately.
handleUnstarred :: Tree String -> Forest String
handleUnstarred t@(Node label children)
| hasStar label = uncurry (++) . handleStarred $ t
| otherwise = children >>= handleUnstarred
handleStarred :: Tree String -> (Forest String, Forest String)
handleStarred t@(Node label children)
| hasStar label = ([Node label (rec >>= fst)], rec >>= snd)
| otherwise = ([], handleUnstarred t)
where rec = map handleStarred children
That's it; handleUnstarred
is the function you want (because the root node is not under a starred node). Try it in ghci:
> handleUnstarred example
[Node {rootLabel = "Beta*", subForest = [Node {rootLabel = "Delta*", subForest = []}]},Node {rootLabel = "Kappa*", subForest = []}]