partage-0.1.0.0: src/NLP/Partage/Tree.hs
{-# LANGUAGE RecordWildCards #-}
-- | This module provides datatypes representing TAG trees.
-- `Tree` is an initial tree, while `AuxTree` represents an auxiliary
-- tree.
module NLP.Partage.Tree
(
-- * Initial tree
Tree (..)
-- , showTree
-- , showTree'
, project
-- * Auxiliary tree
, AuxTree (..)
-- ** Path
, Path
, follow
-- -- * Combining operations
-- -- ** Substitution
-- , subst
-- -- ** Adjoining
-- , adjoin
-- -- * Derivation
-- , Deriv
-- , Trans
-- , derive
-- -- * Traversal
-- , walk
) where
-- import Control.Applicative ((<$>))
-- import Control.Arrow (first)
import Control.Monad (foldM)
-- | A tree with values of type @a@ (/non-termianls/) kept in
-- branching nodes, and values of type @b@ (/terminals/) kept in leaf
-- nodes
data Tree a b
-- | Branching node with a non-terminal symbol
= Branch
{ labelI :: a
-- ^ The non-terminal kept in the branching node
, subTrees :: [Tree a b]
-- ^ The list of subtrees
}
-- | Leaf node with a terminal symbol
| Leaf
{ labelF :: b
-- ^ The terminal symbol
}
deriving (Show, Eq, Ord)
-- | List of frontier values.
toWord :: Tree a b -> [b]
toWord t = case t of
Branch{..} -> concatMap toWord subTrees
Leaf{..} -> [labelF]
-- | Projection of a tree: the list of terminal symbols in its
-- leaves
project :: Tree a b -> [b]
project = toWord
-- -- | Replace the tree on the given position.
-- replaceChild :: Tree a b -> Int -> Tree a b -> Tree a b
-- replaceChild t@INode{..} k t' = t { subTrees = replace subTrees k t' }
-- replaceChild _ _ _ = error "replaceChild: frontier node"
-- -- | Show a tree given the showing functions for label values.
-- showTree :: (a -> String) -> (b -> String) -> Tree a b -> String
-- showTree f g = unlines . go
-- where
-- go t = case t of
-- INode{..} -> ("INode " ++ f labelI)
-- : map (" " ++) (concatMap go subTrees)
-- FNode{..} -> ["FNode " ++ g labelF]
--
--
-- -- | Like `showTree`, but using the default `Show` instances
-- -- to present label values.
-- showTree' :: (Show a, Show b) => Tree a b -> String
-- showTree' = showTree show show
---------------------------------------------------------------------
-- Path
---------------------------------------------------------------------
-- | A path indicates a particular node in a tree and can be used to
-- extract a particular subtree of the tree (see `follow`).
-- For instance, @[]@ designates the entire tree, @[0]@ the first
-- child, and @[1,3]@ the fourth child of the second child of the
-- underlying tree.
type Path = [Int]
-- | Follow the path to a particular subtree.
follow :: Path -> Tree a b -> Maybe (Tree a b)
follow = flip $ foldM step
-- | Follow one step of the `Path`.
step :: Tree a b -> Int -> Maybe (Tree a b)
step (Leaf _) _ = Nothing
step (Branch _ xs) k = xs !? k
---------------------------------------------------------------------
-- Substitution
---------------------------------------------------------------------
-- -- | Perform substitution on a tree. It is neither whether
-- -- the path indicates a leaf, nor if its symbol is identical to the
-- -- symbol of the root of the substituted tree.
-- subst
-- :: Path -- ^ Place of the substitution
-- -> Tree a b -- ^ Tree to be substituted
-- -> Tree a b -- ^ Original tree
-- -> Maybe (Tree a b) -- ^ Resulting tree (or `Nothing`
-- -- if substitution not possible)
-- subst (k:ks) st t = do
-- replaceChild t k <$> (step t k >>= subst ks st)
-- subst [] st _ = Just st
---------------------------------------------------------------------
-- Adjoining
---------------------------------------------------------------------
-- | An auxiliary tree
data AuxTree a b = AuxTree
{ auxTree :: Tree a b
-- ^ The underlying initial tree
, auxFoot :: Path
-- ^ The path to the foot node. Beware that currently it is
-- possible to use the `AuxTree` constructor to build an invalid
-- auxiliary tree, i.e. with an incorrect `auxFoot` value.
} deriving (Show, Eq, Ord)
-- -- | Perform adjoining operation on a tree.
-- adjoin
-- :: Path -- ^ Where to adjoin
-- -> AuxTree a b -- ^ Tree to be adjoined
-- -> Tree a b -- ^ Tree with the node to be modified
-- -> Maybe (Tree a b) -- ^ Resulting tree
-- adjoin (k:ks) aux t = do
-- replaceChild t k <$> (step t k >>= adjoin ks aux)
-- adjoin [] AuxTree{..} t = do
-- subst auxFoot t auxTree
-- ---------------------------------------------------------------------
-- -- Derivation
-- ---------------------------------------------------------------------
--
--
-- -- | A derived tree is constructed by applying a sequence of
-- -- transforming (substitution or adjoining) rules on particular
-- -- positions of a tree. The `Deriv` sequence represents a
-- -- derivation process. One could also construct a derivation
-- -- tree, which to some extent abstracts over the particular order
-- -- of derivations (when it doesn't matter).
-- type Deriv a b = [(Path, Trans a b)]
--
--
-- -- | Transformation of a tree.
-- type Trans a b = Either (Tree a b) (AuxTree a b)
--
--
-- -- | Derive a tree.
-- derive :: Deriv a b -> Tree a b -> Maybe (Tree a b)
-- derive =
-- flip $ foldM m
-- where
-- m t (pos, op) = case op of
-- Left x -> subst pos x t
-- Right x -> adjoin pos x t
---------------------------------------------------------------------
-- Traversal
---------------------------------------------------------------------
-- -- | Return all tree paths with corresponding subtrees.
-- walk :: Tree a b -> [(Path, Tree a b)]
-- walk =
-- map (first reverse) . go []
-- where
-- go acc n@INode{..} = (acc, n) : concat
-- [ go (k:acc) t
-- | (k, t) <- zip [0..] subTrees ]
-- go acc n@FNode{..} = [(acc, n)]
---------------------------------------------------------------------
-- Misc
---------------------------------------------------------------------
-- | Maybe a k-th element of a list.
(!?) :: [a] -> Int -> Maybe a
(x:xs) !? k
| k > 0 = xs !? (k-1)
| otherwise = Just x
[] !? _ = Nothing
-- -- | Replace the k-th element of a list. If the given position is
-- -- outside of the list domain, the returned list will be unchanged.
-- -- It the given index is negative, the first element will be
-- -- replaced.
-- replace :: [a] -> Int -> a -> [a]
-- replace (x:xs) k y
-- | k > 0 = x : replace xs (k - 1) y
-- | otherwise = y : xs
-- replace [] _ _ = []