Skip to content

Commit

Permalink
Adapts to "ListT done right". Fixes #36.
Browse files Browse the repository at this point in the history
* New (light) dependency list-t
* Improves naming and documentation in Control.Monad.Trans.MSF.List
* Adds module to package
  • Loading branch information
turion committed Dec 29, 2017
1 parent 62b88cf commit 1a3b442
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 21 deletions.
3 changes: 2 additions & 1 deletion dunai.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,8 @@ library
build-depends: base >=4.6 && < 5,
transformers,
transformers-base,
MonadRandom
MonadRandom,
list-t
hs-source-dirs: src
default-language: Haskell2010
ghc-options: -Wall -fno-warn-unused-do-bind
Expand Down
86 changes: 66 additions & 20 deletions src/Control/Monad/Trans/MSF/List.hs
Original file line number Diff line number Diff line change
@@ -1,34 +1,80 @@
-- | The 'ListT' monad transformer allows for branching effects.
-- For 'MSF's, this means that the continuation can branch in any tick.
-- This opens a (non-exhaustive) lists of possibilities:
--
-- * Several stream functions can run in parallel
-- * A stream function can split up into several ones
-- (e.g. in a simulation, this would correspond to the creation of objects)
-- * A stream function can decide to stop and delete itself
--
-- Some of the most important operations are given by the 'ArrowPlus' instance
-- of 'MSF's, which is usually available whenever 'ListT' is in the
-- transformer stack.
-- For example:
--
-- * @zeroArrow :: MSF (ListT m) a b@ corresponds to an empty list
-- of continuations
-- * @(\<+\>) :: MSF (ListT m) a b -> MSF (ListT m) a b -> MSF (ListT m) a b@
-- runs the two 'MSF's in parallel by appending the continuations.
--
-- Note though that the 'Monad' instance of lists is given by 'concat',
-- i.e. performing 'ListT' effects in subsequent ticks will result
-- in the cartesian products of the individual effects.
--
-- This module uses "'ListT' done right" as provided by the @list-t@ package.

module Control.Monad.Trans.MSF.List
( module Control.Monad.Trans.MSF.List
, module Control.Monad.Trans.List
, module ListT
) where

-- External
import Control.Monad.Trans.List
hiding (liftCallCC, liftCatch) -- Avoid conflicting exports
-- base
import Control.Arrow

-- list-t
import ListT

-- Internal
import Data.MonadicStreamFunction

-- * List monad

-- * Entering the 'ListT' monad transformer

-- | For each input list element, create a cartesian product of identity arrows.
--
-- For example:
--
-- @
-- >>> let lists = [ [1,2,3], [10], [100, 101], [], [1000] ] :: [[Int]]
-- >>> embed (collect inListT >>> arrM print) lists
-- [1,2,3]
-- [10,10,10]
-- [100,101,100,101,100,101]
-- []
-- []
-- ...
-- @

inListT :: Monad m => MSF (ListT m) [a] a
inListT = arrM $ ListT . return
inListT = arrM fromFoldable

-- | Run several 'MSF's jointly in the 'ListT' monad.
jointly :: Monad m => [MSF m a b] -> MSF (ListT m) a b
jointly = foldl (<+>) zeroArrow . map liftMSFTrans


-- * Leaving the 'ListT' transformer

-- Name alternative (in the article): collect
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 (runListT . flip unMSF a) msfs
return (bs, widthFirst' msfs')
-- | Broadcasts the @a@ input to all 'MSF's
-- and performs a width-first traversal to collect the results.
collect :: (Functor m, Monad m) => MSF (ListT m) a b -> MSF m a [b]
collect msf = collect' [msf] where
collect' msfs = MSF $ \a -> do
(bs, msfs') <- unzip . concat <$> mapM (toList . flip unMSF a) msfs
return (bs, collect' msfs')

-- * Utilities implemented in terms of 'ListT'

-- Name alternatives: "choose", "parallely" (problematic because it's not multicore)
sequenceS :: Monad m => [MSF m a b] -> MSF (ListT m) a b
sequenceS msfs = MSF $ \a -> ListT $ sequence $ apply a <$> msfs
where
apply a msf = do
(b, msf') <- unMSF msf a
return (b, sequenceS [msf'])
-- sequenceS = foldl (<+>) arrowzero . map liftMSFTrans
-- | Run several 'MSF's jointly and collect the results.
sequenceS :: Monad m => [MSF m a b] -> MSF m a [b]
sequenceS = collect . jointly

0 comments on commit 1a3b442

Please sign in to comment.