{- Helpers for the manipulation of rose trees. Throughout, the _trunk_ refers to successive first children in the tree. For example, in the tree > Node a [ Node b [], Node c [Node d []] ] the nodes in the trunk are [a,b] (note that d is not the first child of b). -} module Dodge.Tree.Polymorphic ( applyToRoot , treeFromPost , treeFromTrunk , splitTrunk , applyToRandomNode , addToTrunk , inorderNumberTree , updateSingleNode ) where import Dodge.RandomHelp import Data.Tree import Control.Monad.State import System.Random import Control.Lens {- | Creates a linear tree. Safe. -} treeFromPost :: [a] -> a -> Tree a treeFromPost [] y = Node y [] treeFromPost (x:xs) y = Node x [treeFromPost xs y] {- | Creates a tree with one trunk branch, input as a list, that ends in another tree. -} treeFromTrunk :: [a] -- ^ The trunk -> Tree a -- ^ The end of the tree -> Tree a treeFromTrunk [] t = t treeFromTrunk (x:xs) t = Node x [treeFromTrunk xs t] {- | Applies a function to the root of a tree. -} applyToRoot :: (a -> a) -> Tree a -> Tree a applyToRoot f (Node t ts) = Node (f t) ts -- find use for? ---- | Consider defining this using generalised recursion patterns --treeSize :: Tree a -> Int --treeSize = length . flatten {- | Applies a function to a specific node determined by a list of indices. Unsafe (partial function). -} applyToNode :: [Int] -> (a -> a) -> Tree a -> Tree a applyToNode [] f t = applyToRoot f t applyToNode (i:is) f (Node x xs) = Node x (ys ++ [applyToNode is f z] ++ zs) where (ys, z:zs) = splitAt i xs -- do not delete: find use for --{- | --Applies a function to the first node along a trunk that satisfies a given property. ---} --applyToSubTrunkBy :: (a -> Bool) -> (Tree a -> Tree a) -> Tree a -> Tree a --applyToSubTrunkBy cond f (Node x (t:ts)) -- | cond x = f (Node x (t:ts)) -- | otherwise = Node x (applyToSubTrunkBy cond f t : ts) --applyToSubTrunkBy _ _ t = t -- gives the list of all updates to a single node updateSingleNode :: (a -> Bool) -> (Tree a -> Tree a) -> Tree a -> [Tree a] updateSingleNode f update t@(Node x ts) | f x = update t : updateChildren | otherwise = updateChildren where updateChildren = map (Node x) (subMap (updateSingleNode f update) ts) subMap :: (a -> [a]) -> [a] -> [[a]] subMap f (x:xs) = (f x <&> (: xs)) ++ ( (x :) <$> subMap f xs ) subMap _ [] = [] --subMap' :: Monad m => (a -> m a) -> [a] -> m [a] --subMap' f (x:xs) = (f x <&> (: xs)) ++ ( (x :) <$> (subMap f xs) ) --subMap' f [] = -- find use for? --zipTree :: Tree a -> Tree b -> Tree (a,b) --zipTree (Node x xs) (Node y ys) = Node (x,y) $ zipWith zipTree xs ys {- | Makes each node into its child number, i.e. the index it has in the list of children of its parent. -} treeChildNums :: Tree a -> Tree Int treeChildNums = setRoot 0 where setRoot :: Int -> Tree a -> Tree Int setRoot i (Node _ xs) = Node i (zipWith setRoot [0..] xs) {- | Makes each node into its path, i.e. the list of indices that, when followed from the root, lead to the node. -} treePaths :: Tree a -> Tree [a] treePaths (Node x xs) = (x :) <$> Node [] (map treePaths xs) {- | Picks a random path in the tree. Uniform probability that the path leads to any specific node. -} randomPath :: RandomGen g => Tree a -> State g [Int] randomPath = takeOne . flatten . treePaths . treeChildNums {- | Apply a function to the value of a node; the node is picked uniformly at random. -} applyToRandomNode :: RandomGen g => (a -> a) -> Tree a -> State g (Tree a) applyToRandomNode f t = do p <- randomPath t return $ applyToNode p f t {- | Add a forest to the end of a tree (along the trunk). -} addToTrunk :: Tree a -> [Tree a] -> Tree a addToTrunk (Node x []) f = Node x f addToTrunk (Node x (t:ts)) f = Node x (addToTrunk t f : ts) {- | Find the depth of a tree along the trunk. -} trunkDepth :: Tree a -> Int trunkDepth (Node _ []) = 0 trunkDepth (Node _ (x:_)) = trunkDepth x + 1 {- | Split a tree at a given point along its trunk. -} splitTrunkAt :: Int -- ^ Split depth -> Tree a -> (Tree a, [Tree a]) splitTrunkAt 0 (Node x xs) = (Node x [],xs) splitTrunkAt i (Node y (x:xs)) = let (t, ts) = splitTrunkAt (i-1) x in (Node y (t : xs) , ts) splitTrunkAt _ (Node _ []) = error "Trying to split to short a trunk" {- | Split a tree at a random point along its trunk. -} splitTrunk :: RandomGen g => Tree a -> State g (Tree a, [Tree a]) splitTrunk t = do i <- state $ randomR (0, trunkDepth t) return $ splitTrunkAt i t -- untested inorderNumberTree :: Tree a -> Tree (a,Int) inorderNumberTree = fst . f 0 where f i (Node x ts) = let (ts',i') = g (i+1) ts in (Node (x,i) ts', i') g i (t:ts) = let (t',i') = f i t (ts',i'') = g i' ts in (t': ts', i'') g i [] = ([], i)