{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances #-}
-- | Module : Data.Monadic.List
-- | Copyright : Chung-chieh Shan, Oleg Kiselyov, and Sebastian Fischer
-- | License : PublicDomain
-- |
-- | Maintainer : Sebastian Fischer (sebf@informatik.uni-kiel.de)
-- | Stability : experimental
-- |
-- | This library provides lists with monadic head and tail as an
-- | example for nested monadic data that can be used with the
-- | combinator @share@ for explicit sharing.
module Data.Monadic.List (
List(..), nil, cons, isEmpty, first, rest
) where
import Control.Monad ( MonadPlus, ap, join )
import Control.Monad.Sharing.Classes ( Trans(..) )
-- | Data type for lists where both the head and tail are monadic.
data List m a = Nil | Cons (m a) (m (List m a))
-- | The empty monadic list.
nil :: Monad m => m (List m a)
nil = return Nil
-- | Constructs a non-empty monadic list.
cons :: Monad m => m a -> m (List m a) -> m (List m a)
cons x xs = return (Cons x xs)
-- | Checks if monadic list is empty.
isEmpty :: Monad m => m (List m a) -> m Bool
isEmpty ml = do l <- ml
case l of
Nil -> return True
Cons _ _ -> return False
-- | Yields the head of a monadic list. Relies on @MonadPlus@ instance
-- | to provide a failing implementation of @fail@.
first :: MonadPlus m => m (List m a) -> m a
first ml = do Cons x _ <- ml; x
-- | Yields the tail of a monadic list. Relies on @MonadPlus@ instance
-- | to provide a failing implementation of @fail@.
rest :: MonadPlus m => m (List m a) -> m (List m a)
rest ml = do Cons _ xs <- ml; xs
-- | This instance allows to use nested monadic lists as argument to
-- | the @Control.Monad.Sharing.share@ combinator.
instance (Monad m, Trans m a b) => Trans m (List m a) (List m b)
where
trans _ Nil = return Nil
trans f (Cons x xs) = return Cons `ap` f x `ap` f xs
-- | This instance enables the function @Control.Monad.Sharing.eval@
-- | to transform nested monadic lists into ordinary Haskell lists.
instance (Monad m, Trans m a b) => Trans m (List m a) [b]
where
trans _ Nil = return []
trans f (Cons x xs) = return (:) `ap` join (f x) `ap` join (f xs)
-- | This instance enables the function @Control.Monad.Sharing.eval@
-- | to transform ordinary Haskell lists into nested monadic lists.
instance (Monad m, Trans m a b) => Trans m [a] (List m b)
where
trans _ [] = return Nil
trans f (x:xs) = return Cons `ap` f (return x) `ap` f (return xs)