------------------------------------------------------------------------------
-- | 
-- Maintainer	: Ralf Laemmel, Joost Visser
-- Stability	: experimental
-- Portability	: portable
--
-- This module is part of 'StrategyLib', a library of functional strategy
-- combinators, including combinators for generic traversal. This module
-- defines auxilliary monadic functions, some of which serve as parametric
-- polymorphic prototypes for actual strategy combinators.

------------------------------------------------------------------------------

module Data.Generics.Strafunski.StrategyLib.MonadicFunctions where

import Control.Monad

------------------------------------------------------------------------------
-- * The identity monad 

-- | Identity type constructor.
newtype Id a = Id a

-- | Unwrap identity type constructor
unId 		:: Id a -> a
unId (Id x) 	 = x

instance Monad Id where
 return = Id
 (Id x) >>= f = f x


------------------------------------------------------------------------------
-- * Recover from partiality

-- | Force success. If the argument value corresponds to failure, 
--   a run-time error will occur.
succeed :: Maybe x -> x
succeed (Just x) = x
succeed Nothing  = error "Didn't succeed!."
 
------------------------------------------------------------------------------
-- * Prototypes for strategy combinators seq, let, choice

-- | Sequential composition of monadic functions
mseq 		:: Monad m => (a -> m b) -> (b -> m c) -> a -> m c
f `mseq` g    	=  \x -> f x >>= g 

-- | Sequential composition with value passing; a kind of monadic let.
mlet 		:: Monad m => (a -> m b) -> (b -> a -> m c) -> a -> m c
f `mlet` g    	=  \x -> f x >>= \y -> g y x

-- | Choice combinator for monadic functions
mchoice 	:: MonadPlus m => (a -> m b) -> (a -> m b) -> a -> m b
f `mchoice` g 	=  \x -> (f x) `mplus` (g x)

------------------------------------------------------------------------------
-- * Guards and conditionals

-- | Type guard described by the argument type of a function.
argtype     :: MonadPlus m => (x -> y) -> x -> m ()
argtype _ _ =  return ()


-- | Type guard described by a type of a value.
valtype :: MonadPlus m => x -> x -> m ()
valtype _ _ = return ()

-- | A kind of monadic conditional.
ifM :: MonadPlus m => m a -> (a -> m c) -> (m c) -> (m c)
ifM ma f mc = ((ma >>= \a -> return (Just a))
               `mplus` (return Nothing)
              ) >>= maybe mc f

------------------------------------------------------------------------------