dunai-0.14.0: src/Control/Monad/Trans/MSF/List.hs
{-# LANGUAGE CPP #-}
-- |
-- Copyright : (c) Ivan Perez and Manuel Baerenz, 2016
-- License : BSD3
-- Maintainer : ivan.perez@keera.co.uk
--
-- 'MSF's with a list monadic layer.
--
-- This module contains functions to work with MSFs that include a 'ListT'
-- monadic layer. MSFs on a list monad may produce multiple outputs and
-- continuations, or none. This enables the possibility for spawning new MSFs,
-- or stopping MSFs, at will.
--
-- A common use case is to be able to dynamically spawn new interactive
-- elements in applications (e.g., a game object that splits in two, or that
-- fires to an enemy).
module Control.Monad.Trans.MSF.List
( module Control.Monad.Trans.MSF.List
, module List
)
where
-- External imports
#if !MIN_VERSION_base(4,8,0)
import Control.Applicative ((<$>))
#endif
import Control.Monad (sequence)
import List.Transformer (ListT (ListT, next), Step (..), fold, select)
import qualified List.Transformer as List
-- Internal imports
import Data.MonadicStreamFunction.InternalCore (MSF (MSF, unMSF))
-- * List monad
-- | Run an 'MSF' in the 'ListT' transformer (i.e., multiple MSFs producing
-- each producing one output), by applying the input stream to each MSF in the
-- list transformer and concatenating the outputs of the MSFs together.
--
-- An MSF in the ListT transformer can spawn into more than one MSF, or none,
-- so the outputs produced at each individual step are not guaranteed to all
-- have the same length.
widthFirst :: (Functor m, Monad m) => MSF (ListT m) a b -> MSF m a [b]
widthFirst msf = widthFirst' [msf]
where
widthFirst' msfs = MSF $ \a -> do
(bs, msfs') <- unzip . concat <$> mapM (toList . flip unMSF a) msfs
return (bs, widthFirst' msfs')
toList :: (Functor m, Monad m) => ListT m a -> m [a]
toList = fmap reverse . fold (flip (:)) [] id
-- | Build an 'MSF' in the 'ListT' transformer by broadcasting the input stream
-- value to each MSF in a given list.
sequenceS :: Monad m => [MSF m a b] -> MSF (ListT m) a b
sequenceS msfs = MSF $ \a -> sequence' $ apply a <$> msfs
where
sequence' :: Monad m => [m a] -> ListT m a
sequence' xs = ListT $ next <$> select =<< sequence xs
apply :: Monad m => a -> MSF m a b -> m (b, MSF (ListT m) a b)
apply a msf = do
(b, msf') <- unMSF msf a
return (b, sequenceS [msf'])
-- | Apply an 'MSF' to every input.
mapMSF :: Monad m => MSF m a b -> MSF m [a] [b]
mapMSF = MSF . consume
where
consume :: Monad m => MSF m a t -> [a] -> m ([t], MSF m [a] [t])
consume sf [] = return ([], mapMSF sf)
consume sf (a:as) = do
(b, sf') <- unMSF sf a
(bs, sf'') <- consume sf' as
b `seq` return (b:bs, sf'')