New monads/MonadSplit
Jump to navigation
Jump to search
> module Control.Monad.MonadSplit where
> import Control.Monad
> import qualified Data.Sequence as S
MonadSplit, in a sense, represents the class of monads which have both
"mplus" and a new decomposition operator: "msplit" such that
l == (msplit l >>= \(x,xs) -> return x `mplus` xs)
> class MonadPlus m => MonadSplit m where
> msplit :: m a -> m (a, m a)
> miszero :: m a -> Bool
> instance MonadSplit [] where
> msplit [] = mzero
> msplit (x:xs) = return (x,xs)
> miszero = null
> instance MonadSplit Maybe where
> msplit Nothing = mzero
> msplit (Just x) = return (x, Nothing)
> miszero Nothing = True
> miszero (Just _) = False
This class allows us to implement several functions which were
previously implemented over lists only.
> foldMSl :: (MonadSplit m) => (a -> b -> m a) -> a -> m b -> m a
> foldMSl m i n | miszero n = return i
> | otherwise = do
> (x,xs) <- msplit n
> i' <- m i x
> foldMSl m i' xs
> foldMSr :: (MonadSplit m) => (a -> b -> m b) -> b -> m a -> m b
> foldMSr m i n | miszero n = return i
> | otherwise = do
> (x,xs) <- msplit n
> i' <- foldMSr m i xs
> m x i'
> scanMSl :: (MonadSplit m) => (a -> b -> m a) -> a -> m b -> m (m a)
> scanMSl m i n | miszero n = return (return i)
> | otherwise = do
> (x,xs) <- msplit n
> i' <- m i x
> return (return i) `mplus` scanMSl m i' xs
> scanMSr :: (MonadSplit m) => (a -> b -> m b) -> b -> m a -> m (m b)
> scanMSr m i n | miszero n = return (return i)
> | otherwise = do
> (x,xs) <- msplit n
> i' <- scanMSr m i xs
> (return . m x =<< i') `mplus` return i'
> initsM :: (MonadSplit m) => m a -> m (m a)
> initsM m | miszero m = return mzero
> | otherwise = return mzero `mplus` do
> (x,xs) <- msplit m
> a <- initsM xs
> return $ return x `mplus` a
> tailsM :: (MonadSplit m) => m a -> m (m a)
> tailsM m | miszero m = return mzero
> | otherwise = msplit m >>= \(x,xs) -> return m `mplus` tailsM xs
With cuts l = zip (inits l) (tails l), cutsM is the equivalent for MonadSplit.
> cutsM :: (MonadSplit m) => m a -> m (m a, m a)
> cutsM m | miszero m = return (mzero, mzero)
> | otherwise = return (mzero, m) `mplus` do
> (x,xs) <- msplit m
> (a,b) <- cutsM xs
> return $ (return x `mplus` a, b)
> insertM :: (MonadSplit m) => a -> m a -> m (m a)
> insertM i m = do
> (a,b) <- cutsM m
> return $ a `mplus` return i `mplus` b
> permuteM :: (MonadSplit m) => m a -> m (m a)
> permuteM m | miszero m = return mzero
> | otherwise = do
> (x,xs) <- msplit m
> xs' <- permuteM xs
> insertM x xs'
As it happens, permuteM can be expressed with foldMSr.
> permuteM2 :: (MonadSplit m) => m b -> m (m b)
> permuteM2 m = foldMSr insertM mzero m
permuteWithDel means to permute the list and all sublists.
> permuteWithDelM m | miszero m = return mzero
> | otherwise = do
> (x,xs) <- msplit m
> xs' <- permuteWithDelM xs
> insertM x xs' `mplus` return xs'
> permuteWithDelM2 m = foldMSr (\x xs -> insertM x xs `mplus` return xs) mzero m
An example instance for another datatype.
> instance MonadSplit S.Seq where
> miszero = S.null
> msplit s = case S.viewl s of
> S.EmptyL -> return (undefined,
> fail "msplit used on empty sequence")
> x S.:< xs -> return (x, xs)
A "generalized" searching function:
g is "generator", a function which accepts the current search space, an
element of input, and produces a new search space.
t is "tester", a function which evaluates generated solutions
and finally, i is "input".
> search :: (MonadSplit s, MonadPlus p) =>
> (b -> p a -> s (p a)) -> (p a -> Bool) -> s b -> s (p a)
> search g t i = (foldMSr g mzero i) >>= (\x -> guard (t x) >> return x)
test1 = search insertM (all (<4))
test1 [1..2] => [[1,2],[2,1]]
test1 [1..4] => []
test2 = search (\x xs -> insertM x xs `mplus` return xs) (all (<4))
test2 [1..4] => [[1,2,3],[2,1,3],[2,3,1],[2,3],[1,3,2],[3,1,2],[3,2,1],
[3,2],[1,3],[3,1],[3],[1,2],[2,1],[2],[1],[]]