content: module ListUtil{-(
  	assoc, concatMap, unfoldr, mapAccuml, union, intersection,
  	chopList, assocDef, lookup, module Maybe,
          rept, tails, groupEq, group, readListLazily, nubEq, elemEq,
  	mix, mapFst,mapSnd)-} where
  
  --   Now report says that it is not ok to hide not exported entries
  import Prelude -- hiding (unfoldr) 
                 
  import Maybe
  import List hiding (union,tails,unfoldr)
  
  breakAt :: (Eq a) => a -> [a] -> ([a], [a])
  breakAt _ [] = ([], [])
  breakAt x (x':xs) =
  	if x == x' then
  	    ([], xs)
  	else
  	    let (ys, zs) = breakAt x xs
  	    in  (x':ys, zs)
  
  -- Read a list lazily (in contrast with reads which requires
  -- to see the ']' before returning the list.
  readListLazily :: (Read a) => String -> [a]
  readListLazily cs = 
      case lex cs of
        [("[",cs)] -> readl' cs
        _          -> error "No leading '['"
      where readl' cs  =
                  case reads cs of
                    [(x,cs)]  -> x : readl cs
                    []        -> error "No parse for list element"
                    _         -> error "Ambigous parse for list element"
            readl cs =
                  case lex cs of
                    [("]",_)]  -> []
                    [(",",cs)] -> readl' cs
                    _          -> error "No ',' or ']'"
  
  -- Lookup an item in an association list.  Apply a function to it if it is found, otherwise return a default value.
  assoc :: (Eq c) => (a -> b) -> b -> [(c, a)] -> c -> b
  assoc f d [] x                       = d
  assoc f d ((x',y):xys) x | x' == x   = f y
                           | otherwise = assoc f d xys x
  
  -- Repeatedly extract (and transform) values until a predicate hold.  Return the list of values.
  unfoldr :: (a -> (b, a)) -> (a -> Bool) -> a -> [b]
  unfoldr f p x | p x       = []
  	      | otherwise = y:unfoldr f p x'
  			      where (y, x') = f x
  
  -- Map, but plumb a state through the map operation.
  mapAccuml :: (a -> b -> (a, c)) -> a -> [b] -> (a, [c])
  mapAccuml f s []     = (s, [])
  mapAccuml f s (x:xs) = (s'', y:ys)
  		       where (s',  y)  = f s x
  			     (s'', ys) = mapAccuml f s' xs
  
  -- Union of sets as lists.
  union :: (Eq a) => [a] -> [a] -> [a]
  union xs ys = xs ++ (ys \\ xs)
  
  -- Intersection of sets as lists.
  intersection :: (Eq a) => [a] -> [a] -> [a]
  --intersection xs ys = [x | x<-xs, x `elem` ys]
  intersection xs ys = filter (\x -> x `elem` ys) xs
  
  --- Functions derived from those above
  
  chopList :: ([a] -> (b, [a])) -> [a] -> [b]
  chopList f l = unfoldr f null l
  
  assocDef :: (Eq a) => [(a, b)] -> b -> a -> b
  assocDef l d x = assoc id d l x
  
  --lookup :: (Eq a) => [(a, b)] -> a -> Maybe b
  --lookup l x = assoc (\x -> Just x) Nothing l x
  
  -- Repeat an element n times
  --rept :: (Integral a) => a -> b -> [b]
  rept 0 _ = []
  rept n x = x : rept (n-1) x
  --rept n x = if n<=0 then [] else x:rept (n-1) x
  
  -- Take all the tails
  tails :: [a] -> [[a]]
  tails []         = []
  tails xxs@(_:xs) = xxs : tails xs
  
  {-
  -- group list elements according to an equality predicate
  groupEq :: (a->a->Bool) -> [a] -> [[a]]
  groupEq eq xs = chopList f xs
  		where f xs@(x:_) = span (eq x) xs
  
  group :: (Eq a) => [a] -> [[a]]
  group xs = groupEq (==) xs
  
  -- Read a list lazily (in contrast with reads which requires
  -- to see the ']' before returning the list.
  readListLazily :: (Text a) => String -> [a]
  readListLazily cs = 
      case lex cs of
        [("[",cs)] -> readl' cs
        _          -> error "No leading '['"
      where readl' cs  =
                  case reads cs of
                    [(x,cs)]  -> x : readl cs
                    []        -> error "No parse for list element"
                    _         -> error "Ambigous parse for list element"
            readl cs =
                  case lex cs of
                    [("]",_)]  -> []
                    [(",",cs)] -> readl' cs
                    _          -> error "No ',' or ']'"
  
  
  nubEq :: (a->a->Bool) -> [a] -> [a]
  nubEq eq l = nub' l []
  	where nub' [] _	    = []
  	      nub' (x:xs) l = if elemEq eq x l then nub' xs l else x : nub' xs (x:l)
  -}
  elemEq :: (a->a->Bool) -> a -> [a] -> Bool
  elemEq eq _ []	   = False
  elemEq eq x (y:ys) = eq x y || elemEq eq x ys
  
  {-
  --{-# SPECIALIZE average :: [Float] -> Float, [Double] -> Double #-}
  average :: (Fractional a) => [a] -> a
  average xs = f xs 0 0
  	where f []     s l = s / fromInt l
  	      f (x:xs) s l = f xs (s+x) (l+1)
  fromInt = id
  -}
  
  mix [] y = []
  mix [x] y = x
  mix (x:xs) y = x ++ y ++ mix xs y
  
  mapFst f [] = []
  mapFst f ((x,y):zs) = (f x,y):mapFst f zs
  
  mapSnd f [] = []
  mapSnd f ((x,y):zs) = (x,f y):mapSnd f zs
  