A mutable tree. This appears to run more efficiently under Hugs, than
using a purely functional one, when performing lots of replace actions 
on a big tree. 
To do: test whether this is really true

\begin{code}
module TreeIO where
import IOExts
import Monad

type TreeIO a = IORef (TreeIO' a)
data TreeIO' a = TreeIO a [TreeIO a]

data SubTree a = SubTree a [SubTree a]
 deriving Show

test = do
 t <- initTreeIO st1
 toSubTree t >>= print
 (mk,dead,above) <- replaceInTree ((== 5) . fst) t
 maybe (print "dead") ($ st1) mk
 print (dead,above)
 toSubTree t >>= print

st1 = SubTree (1,"a") [SubTree (2,"b") [],SubTree (3,"c") [],SubTree (4,"d") [],SubTree (5,"e") []]

-- make a tree
initTreeIO :: SubTree a -> IO (TreeIO a)
initTreeIO (SubTree a cs) = do
 ts <- mapM initTreeIO cs
 newIORef $ TreeIO a ts

-- replace with the first element satisfying the boolean predicate with
-- the new subtree in the given tree. Return the new tree, and the list
-- of elements that were in the old removed subtree

replaceInTree :: (a -> Bool) -> TreeIO a 
              -> IO (Maybe (SubTree a -> IO ()),[a],[a])
replaceInTree (p :: a -> Bool)  tio = register tio []
  where
   register :: TreeIO a -> [a] 
            -> IO (Maybe (SubTree a -> IO ()),[a],[a])
   register tref abv = do
    (TreeIO a cs) <- readIORef tref 
    if p a then do
      as <- preorder tref
      return (Just $ \(SubTree a cs) -> do
			cs <- mapM initTreeIO cs
			writeIORef tref (TreeIO a cs),
	      as,abv)
     else 
      regList cs (a:abv)

   regList :: [TreeIO a] -> [a]
           -> IO (Maybe (SubTree a -> IO ()),
		  [a],[a])
   regList [] abv = return (Nothing,[],[])
   regList (t:ts) abv = do
     info@(ret,as,abv') <- register t abv
     case ret of
      Nothing -> regList ts abv
      Just op -> return info 

preorder :: TreeIO a -> IO [a]
preorder tref = do
 (TreeIO a cs) <- readIORef tref
 as <- mapM preorder cs
 return $ a:concat as

toSubTree :: TreeIO a -> IO (SubTree a)
toSubTree tref = do
 (TreeIO a cs) <- readIORef tref
 cs <- mapM toSubTree cs
 return $ SubTree a cs
\end{code}


replaceInTree :: (a -> Bool) -> SubTree a -> TreeIO a -> IO (TreeIO a,[a])
replaceInTree p (s :: SubTree a) tio = do
 st <- initTreeIO s
 fmap fst $ register st tio
  where
   register :: TreeIO a -> TreeIO a -> IO ((TreeIO a,[a]),Bool)
   register st t@(TreeIO a ref) = 
    if p a then do
      as <- preorder t
      return ((st,as),True)
    else do
      cs <- readIORef ref
      (ts,as,b) <- regList st [] cs
      when b $ writeIORef ref ts
      return ((t,as),b)
      
   regList :: TreeIO a -> [TreeIO a] -> [TreeIO a] -> IO ([TreeIO a],[a],Bool)
   regList st vs [] = return (reverse vs,[],False)
   regList st' vs (t:ts) = do
     ((st,as),b) <- register st' t
     if b then 
       return (reverse (st:vs) ++ ts,as,b)
      else
       regList st' (st:vs) ts 

{-

-}
