{- |
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'
