content: {- |
  Module      : Language.Egison.MList
  Licence     : MIT
  
  This module provides definition and utility functions for monadic list.
  -}
  
  module Language.Egison.MList
    ( MList (..)
    , fromList
    , fromSeq
    , fromMList
    , msingleton
    , mfoldr
    , mappend
    , mconcat
    , mmap
    , mfor
    , mAny
    ) where
  
  import           Data.Sequence (Seq)
  import           Prelude       hiding (mappend, mconcat)
  
  data MList m a = MNil | MCons a (m (MList m a))
  
  instance Show a => Show (MList m a) where
    show MNil        = "MNil"
    show (MCons x _) = "(MCons " ++ show x ++ " ...)"
  
  fromList :: Monad m => [a] -> MList m a
  fromList = foldr f MNil
   where f x xs = MCons x $ return xs
  
  fromSeq :: Monad m => Seq a -> MList m a
  fromSeq = foldr f MNil
   where f x xs = MCons x $ return xs
  
  fromMList :: Monad m => MList m a -> m [a]
  fromMList = mfoldr f $ return []
    where f x xs = (x:) <$> xs
  
  msingleton :: Monad m => a -> MList m a
  msingleton = flip MCons $ return MNil
  
  mfoldr :: Monad m => (a -> m b -> m b) -> m b -> MList m a -> m b
  mfoldr _ init MNil         = init
  mfoldr f init (MCons x xs) = f x (xs >>= mfoldr f init)
  
  mappend :: Monad m => MList m a -> m (MList m a) -> m (MList m a)
  mappend xs ys = mfoldr ((return .) . MCons) ys xs
  
  mconcat :: Monad m => MList m (MList m a) -> m (MList m a)
  mconcat = mfoldr mappend $ return MNil
  
  mmap :: Monad m => (a -> m b) -> MList m a -> m (MList m b)
  mmap f = mfoldr g $ return MNil
    where g x xs = flip MCons xs <$> f x
  
  mfor :: Monad m => MList m a -> (a -> m b) -> m (MList m b)
  mfor = flip mmap
  
  mAny :: Monad m => (a -> m Bool) -> MList m a -> m Bool
  mAny _ MNil = return False
  mAny p (MCons x xs) = do
    b <- p x
    if b
     then return True
     else do xs' <- xs
             mAny p xs'
  