diff --git a/CHANGELOG b/CHANGELOG
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,18 @@
+2022-06-21 Ivan Perez <ivan.perez@keera.co.uk>
+        * dunai.cabal: Version bump (0.8.3) (#302).
+        * src/: Simplify implementation of switch (#276), remove redundant
+          imports (#281), remove redundant pragma (#282), use external
+          Void type (#79), remove redundant imports (#283), disable warning
+          pertaining to orphan instances (#284), style fixes (partial) (#285),
+          fix missing re-export of Control.Arrow (#286), further style fixes
+          (partial) (#287), avoid name shadowing (#291), remove outdated
+          comments (#289), remove unused pragmas (#290), remove unnecessary
+          comment (#293), reimplement function without TupleSections (#293),
+          standardize haddock comment (#294), add missing documentation (#288),
+          disable warning due to use of ListT (#297), fix oudated comment
+          (#299), horizontal alignment style changes (#301).
+        * README.md: Re-structure README (#300).
+
 2022-04-21 Ivan Perez <ivan.perez@keera.co.uk>
         * dunai.cabal: Version bump (0.8.2) (#280), syntax rules (#271),
           declare CHANGELOG (#273), declare subdir of source-repository (#272).
diff --git a/dunai.cabal b/dunai.cabal
--- a/dunai.cabal
+++ b/dunai.cabal
@@ -30,7 +30,7 @@
 build-type:    Simple
 
 name:          dunai
-version:       0.8.2
+version:       0.8.3
 author:        Ivan Perez, Manuel Bärenz
 maintainer:    ivan.perez@keera.co.uk
 homepage:      https://github.com/ivanperez-keera/dunai
@@ -140,7 +140,8 @@
 
   if impl(ghc <= 7.8.4)
     build-depends:
-      transformers-compat
+        transformers-compat
+      , void
 
 
 test-suite hlint
diff --git a/src/Control/Arrow/Util.hs b/src/Control/Arrow/Util.hs
--- a/src/Control/Arrow/Util.hs
+++ b/src/Control/Arrow/Util.hs
@@ -6,15 +6,16 @@
 -- Utility functions to work with 'Arrow's.
 module Control.Arrow.Util where
 
-import Control.Arrow
+-- External imports
+import Control.Arrow (Arrow, arr, (&&&), (>>^), (^<<))
 
 -- | Constantly produce the same output.
 constantly :: Arrow a => b -> a c b
 constantly = arr . const
 {-# INLINE constantly #-}
 
--- * Apply functions at the end.
---
+-- * Apply functions at the end
+
 -- | Alternative name for '^<<'.
 elementwise :: Arrow a => (c -> d) -> a b c -> a b d
 elementwise = (^<<)
diff --git a/src/Control/Monad/Trans/MSF.hs b/src/Control/Monad/Trans/MSF.hs
--- a/src/Control/Monad/Trans/MSF.hs
+++ b/src/Control/Monad/Trans/MSF.hs
@@ -1,4 +1,3 @@
-{-# LANGUAGE Rank2Types #-}
 -- |
 -- Copyright  : (c) Ivan Perez and Manuel Baerenz, 2016
 -- License    : BSD3
@@ -16,6 +15,7 @@
     )
   where
 
+-- Internal imports
 import Control.Monad.Trans.MSF.Except
 import Control.Monad.Trans.MSF.Maybe
 import Control.Monad.Trans.MSF.Random
diff --git a/src/Control/Monad/Trans/MSF/Except.hs b/src/Control/Monad/Trans/MSF/Except.hs
--- a/src/Control/Monad/Trans/MSF/Except.hs
+++ b/src/Control/Monad/Trans/MSF/Except.hs
@@ -1,7 +1,6 @@
-{-# LANGUAGE Arrows        #-}
-{-# LANGUAGE CPP           #-}
-{-# LANGUAGE Rank2Types    #-}
-{-# LANGUAGE TupleSections #-}
+{-# LANGUAGE Arrows     #-}
+{-# LANGUAGE CPP        #-}
+{-# LANGUAGE Rank2Types #-}
 -- |
 -- Copyright  : (c) Ivan Perez and Manuel Baerenz, 2016
 -- License    : BSD3
@@ -12,22 +11,30 @@
 -- module gives ways to throw exceptions in various ways, and to handle them
 -- through a monadic interface.
 module Control.Monad.Trans.MSF.Except
-  ( module Control.Monad.Trans.MSF.Except
-  , module Control.Monad.Trans.Except
-  ) where
+    ( module Control.Monad.Trans.MSF.Except
+    , module Control.Monad.Trans.Except
+    )
+  where
 
--- External
-import           Control.Applicative
+-- External imports
+#if !MIN_VERSION_base(4,8,0)
+import           Control.Applicative        (Applicative (..), (<$>))
+#endif
+
+import           Control.Arrow              (arr, returnA, (<<<), (>>>))
 import qualified Control.Category           as Category
 import           Control.Monad              (ap, liftM)
-import           Control.Monad.Trans.Class
+import           Control.Monad.Trans.Class  (lift)
 import           Control.Monad.Trans.Except hiding (liftCallCC, liftListen,
                                              liftPass)
-import           Control.Monad.Trans.Maybe
+import           Control.Monad.Trans.Maybe  (MaybeT, runMaybeT)
+import           Data.Void                  (Void)
 
--- Internal
-import Data.MonadicStreamFunction
-import Data.MonadicStreamFunction.InternalCore
+-- Internal imports
+import Data.MonadicStreamFunction              (arrM, constM, count, feedback,
+                                                liftTransS, mapMaybeS, morphS,
+                                                reactimate)
+import Data.MonadicStreamFunction.InternalCore (MSF (MSF, unMSF))
 
 -- External, necessary for older base versions
 #if __GLASGOW_HASKELL__ < 802
@@ -49,8 +56,8 @@
   then throwS  -< e
   else returnA -< a
 
--- | Variant of 'throwOnCond' for Kleisli arrows.
--- | Throws the exception when the input is 'True'.
+-- | Throws the exception when the input is 'True'. Variant of 'throwOnCond'
+-- for Kleisli arrows.
 throwOnCondM :: Monad m => (a -> m Bool) -> e -> MSF (ExceptT e m) a a
 throwOnCondM cond e = proc a -> do
   b <- arrM (lift . cond) -< a
@@ -68,8 +75,8 @@
   then throwS  -< e
   else returnA -< ()
 
--- | When the input is @Just e@, throw the exception @e@.
---   (Does not output any actual data.)
+-- | When the input is @Just e@, throw the exception @e@. (Does not output any
+-- actual data.)
 throwMaybe :: Monad m => MSF (ExceptT e m) (Maybe e) (Maybe a)
 throwMaybe = mapMaybeS throwS
 
@@ -85,78 +92,74 @@
 pass :: Monad m => MSF (ExceptT e m) a a
 pass = Category.id
 
--- | Converts an 'MSF' in 'MaybeT' to an 'MSF' in 'ExceptT'.
---   Whenever 'Nothing' is thrown, throw @()@ instead.
+-- | Converts an 'MSF' in 'MaybeT' to an 'MSF' in 'ExceptT'. Whenever
+-- 'Nothing' is thrown, throw @()@ instead.
 maybeToExceptS :: (Functor m, Monad m)
                => MSF (MaybeT m) a b -> MSF (ExceptT () m) a b
 maybeToExceptS = morphS (ExceptT . (maybe (Left ()) Right <$>) . runMaybeT)
 
 -- * Catching exceptions
 
--- | Catch an exception in an 'MSF'. As soon as an exception occurs,
---   the current continuation is replaced by a new 'MSF', the exception handler,
---   based on the exception value.
---   For exception catching where the handler can throw further exceptions,
---   see 'MSFExcept' further below.
+-- | Catch an exception in an 'MSF'. As soon as an exception occurs, the
+-- current continuation is replaced by a new 'MSF', the exception handler,
+-- based on the exception value. For exception catching where the handler can
+-- throw further exceptions, see 'MSFExcept' further below.
 catchS :: Monad m => MSF (ExceptT e m) a b -> (e -> MSF m a b) -> MSF m a b
 catchS msf f = safely $ do
   e <- try msf
   safe $ f e
 
 -- | Similar to Yampa's delayed switching. Loses a @b@ in case of an exception.
-untilE :: Monad m => MSF m a b -> MSF m b (Maybe e)
+untilE :: Monad m
+       => MSF m a b
+       -> MSF m b (Maybe e)
        -> MSF (ExceptT e m) a b
 untilE msf msfe = proc a -> do
   b  <- liftTransS msf  -< a
   me <- liftTransS msfe -< b
   inExceptT -< ExceptT $ return $ maybe (Right b) Left me
 
--- TODO This needs to be renamed as 'runExceptS'!
--- 'exceptS' would have type @MSF m a (Either e b) -> MSF (ExceptT e m) a b@
 -- | Escape an 'ExceptT' layer by outputting the exception whenever it occurs.
---   If an exception occurs, the current 'MSF' continuation is tested again
---   on the next input.
+-- If an exception occurs, the current 'MSF' continuation is tested again on
+-- the next input.
 exceptS :: (Functor m, Monad m) => MSF (ExceptT e m) a b -> MSF m a (Either e b)
 exceptS = transG return $ const $ fmap f . runExceptT
   where
     f (Left e)       = (Left e , Nothing)
     f (Right (b, c)) = (Right b, Just c )
 
--- | Embed an 'ExceptT' value inside the 'MSF'.
---   Whenever the input value is an ordinary value,
---   it is passed on. If it is an exception, it is raised.
+-- | Embed an 'ExceptT' value inside the 'MSF'. Whenever the input value is an
+-- ordinary value, it is passed on. If it is an exception, it is raised.
 inExceptT :: Monad m => MSF (ExceptT e m) (ExceptT e m a) a
 inExceptT = arrM id
 
--- | In case an exception occurs in the first argument,
---   replace the exception by the second component of the tuple.
+-- | In case an exception occurs in the first argument, replace the exception
+-- by the second component of the tuple.
 tagged :: Monad m => MSF (ExceptT e1 m) a b -> MSF (ExceptT e2 m) (a, e2) b
 tagged msf = runMSFExcept $ do
   _       <- try $ msf <<< arr fst
   (_, e2) <- currentInput
   return e2
 
-
 -- * Monad interface for Exception MSFs
 
--- | 'MSF's with an 'ExceptT' transformer layer
---   are in fact monads /in the exception type/.
+-- | 'MSF's with an 'ExceptT' transformer layer are in fact monads /in the
+-- exception type/.
 --
 --   * 'return' corresponds to throwing an exception immediately.
---   * '>>=' is exception handling:
---     The first value throws an exception,
---     while the Kleisli arrow handles the exception
---     and produces a new signal function,
---     which can throw exceptions in a different type.
+--   * '>>=' is exception handling: The first value throws an exception, while
+--     the Kleisli arrow handles the exception and produces a new signal
+--     function, which can throw exceptions in a different type.
 --   * @m@: The monad that the 'MSF' may take side effects in.
 --   * @a@: The input type
 --   * @b@: The output type
 --   * @e@: The type of exceptions that can be thrown
 newtype MSFExcept m a b e = MSFExcept { runMSFExcept :: MSF (ExceptT e m) a b }
 
--- | An alias for the 'MSFExcept' constructor,
--- used to enter the 'MSFExcept' monad context.
--- Execute an 'MSF' in 'ExceptT' until it raises an exception.
+-- | Execute an 'MSF' in 'ExceptT' until it raises an exception.
+--
+-- An alias for the 'MSFExcept' constructor, used to enter the 'MSFExcept'
+-- monad context.
 try :: MSF (ExceptT e m) a b -> MSFExcept m a b e
 try = MSFExcept
 
@@ -183,40 +186,34 @@
 
 -- | Execute an MSF and, if it throws an exception, recover by switing to a
 -- second MSF.
-handleExceptT
-  :: Monad m
-  => MSF (ExceptT e1 m) a b
-  -> (e1 -> MSF (ExceptT e2 m) a b)
-  -> MSF (ExceptT e2 m) a b
+handleExceptT :: Monad m
+              => MSF (ExceptT e1 m) a b
+              -> (e1 -> MSF (ExceptT e2 m) a b)
+              -> MSF (ExceptT e2 m) a b
 handleExceptT msf f = flip handleGen msf $ \a mbcont -> do
   ebcont <- lift $ runExceptT mbcont
   case ebcont of
     Left e          -> unMSF (f e) a
     Right (b, msf') -> return (b, handleExceptT msf' f)
 
-
-
--- | The empty type. As an exception type, it encodes "no exception possible".
-data Empty
-
--- | If no exception can occur, the 'MSF' can be executed without the 'ExceptT' layer.
-safely :: Monad m => MSFExcept m a b Empty -> MSF m a b
+-- | If no exception can occur, the 'MSF' can be executed without the 'ExceptT'
+-- layer.
+safely :: Monad m => MSFExcept m a b Void -> MSF m a b
 safely (MSFExcept msf) = morphS fromExcept msf
   where
-    -- We can assume that the pattern @Left e@ will not occur,
-    -- since @e@ would have to be of type @Empty@.
+    -- We can assume that the pattern @Left e@ will not occur, since @e@ would
+    -- have to be of type @Void@.
     fromExcept ma = do
       rightMa <- runExceptT ma
       return $ fromRight (error "safely: Received `Left`") rightMa
 
--- | An 'MSF' without an 'ExceptT' layer never throws an exception,
---   and can thus have an arbitrary exception type.
+-- | An 'MSF' without an 'ExceptT' layer never throws an exception, and can
+-- thus have an arbitrary exception type.
 safe :: Monad m => MSF m a b -> MSFExcept m a b e
 safe = try . liftTransS
 
 -- | Inside the 'MSFExcept' monad, execute an action of the wrapped monad.
---   This passes the last input value to the action,
---   but doesn't advance a tick.
+-- This passes the last input value to the action, but doesn't advance a tick.
 once :: Monad m => (a -> m e) -> MSFExcept m a b e
 once f = try $ arrM (lift . f) >>> throwS
 
@@ -224,8 +221,8 @@
 once_ :: Monad m => m e -> MSFExcept m a b e
 once_ = once . const
 
--- | Advances a single tick with the given Kleisli arrow,
---   and then throws an exception.
+-- | Advances a single tick with the given Kleisli arrow, and then throws an
+-- exception.
 step :: Monad m => (a -> m (b, e)) -> MSFExcept m a b e
 step f = try $ proc a -> do
   n      <- count           -< ()
@@ -233,29 +230,22 @@
   _      <- throwOn'        -< (n > (1 :: Int), e)
   returnA                   -< b
 
--- | Advances a single tick outputting the value,
---   and then throws '()'.
+-- | Advances a single tick outputting the value, and then throws '()'.
 step_ :: Monad m => b -> MSFExcept m a b ()
-step_ = step . const . return . (, ())
+step_ b = step $ const $ return (b, ())
 
--- | Converts a list to an 'MSFExcept',
---   which outputs an element of the list at each step,
---   throwing '()' when the list ends.
+-- | Converts a list to an 'MSFExcept', which outputs an element of the list at
+-- each step, throwing '()' when the list ends.
 listToMSFExcept :: Monad m => [b] -> MSFExcept m a b ()
 listToMSFExcept = mapM_ step_
 
 -- * Utilities definable in terms of 'MSFExcept'
 
--- TODO This is possibly not the best location for these functions,
--- but moving them to Data.MonadicStreamFunction.Util would form an import cycle
--- that could only be broken by moving a few things to Data.MonadicStreamFunction.Core
--- (that probably belong there anyways).
-
 -- | Extract an 'MSF' from a monadic action.
 --
--- Runs a monadic action that produces an 'MSF' on the first iteration/step, and
--- uses that 'MSF' as the main signal function for all inputs (including the
--- first one).
+-- Runs a monadic action that produces an 'MSF' on the first iteration/step,
+-- and uses that 'MSF' as the main signal function for all inputs (including
+-- the first one).
 performOnFirstSample :: Monad m => m (MSF m a b) -> MSF m a b
 performOnFirstSample sfaction = safely $ do
   msf <- once_ sfaction
@@ -274,19 +264,24 @@
 -- | Run first MSF until the second value in the output tuple is @Just c@ (for
 -- some @c@), then start the second MSF.
 --
--- Analog to Yampa's [@switch@](https://hackage.haskell.org/package/Yampa/docs/FRP-Yampa-Switches.html#v:switch),
+-- Analog to Yampa's
+-- [@switch@](https://hackage.haskell.org/package/Yampa/docs/FRP-Yampa-Switches.html#v:switch),
 -- with 'Maybe' instead of @Event@.
 switch :: Monad m => MSF m a (b, Maybe c) -> (c -> MSF m a b) -> MSF m a b
-switch sf f = catchS ef  f
+switch sf f = catchS ef f
   where
+    -- Run sf, throwing an exception if there is a no-Nothing value in the
+    -- second element of the pair, and returning the first element otherwise.
     ef = proc a -> do
-           (b,me)  <- liftTransS sf -< a
-           inExceptT -< ExceptT $ return $ maybe (Right b) Left me
+           (b, me)  <- liftTransS sf  -< a
+           throwMaybe                 -< me
+           returnA                    -< b
 
 -- | Run first MSF until the second value in the output tuple is @Just c@ (for
 -- some @c@), then start the second MSF.
 --
--- Analog to Yampa's [@dswitch@](https://hackage.haskell.org/package/Yampa/docs/FRP-Yampa-Switches.html#v:dSwitch),
+-- Analog to Yampa's
+-- [@dswitch@](https://hackage.haskell.org/package/Yampa/docs/FRP-Yampa-Switches.html#v:dSwitch),
 -- with 'Maybe' instead of @Event@.
 dSwitch :: Monad m => MSF m a (b, Maybe c) -> (c -> MSF m a b) -> MSF m a b
 dSwitch sf f = catchS ef f
@@ -305,11 +300,14 @@
        -> MSF m1 a1 b1
        -> MSF m2 a2 b2
 transG transformInput transformOutput msf = go
-  where go = MSF $ \a2 -> do
-               (b2, msf') <- transformOutput a2 $ unMSF msf =<< transformInput a2
-               case msf' of
-                 Just msf'' -> return (b2, transG transformInput transformOutput msf'')
-                 Nothing    -> return (b2, go)
+  where
+    go = MSF $ \a2 -> do
+           (b2, msf') <- transformOutput a2 $ unMSF msf =<< transformInput a2
+           case msf' of
+             Just msf'' ->
+               return (b2, transG transformInput transformOutput msf'')
+             Nothing ->
+               return (b2, go)
 
 -- | Use a generic handler to handle exceptions in MSF processing actions.
 handleGen :: (a -> m1 (b1, MSF m1 a b1) -> m2 (b2, MSF m2 a b2))
diff --git a/src/Control/Monad/Trans/MSF/List.hs b/src/Control/Monad/Trans/MSF/List.hs
--- a/src/Control/Monad/Trans/MSF/List.hs
+++ b/src/Control/Monad/Trans/MSF/List.hs
@@ -1,42 +1,71 @@
 {-# LANGUAGE CPP #-}
+-- The following warning id disabled so that we do not see warnings during
+-- compilation caused by the intentional use of ListT.
+#if __GLASGOW_HASKELL__ < 800
+{-# OPTIONS_GHC -fno-warn-warnings-deprecations #-}
+#else
+{-# OPTIONS_GHC -Wno-deprecations #-}
+#endif
 -- |
 -- 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).
+--
+-- WARNING: the ListT transformer is considered dangerous, and imposes
+-- additional constraints on the inner monad in order for the combination of
+-- the monad and the transformer to be a monad. Use at your own risk.
 module Control.Monad.Trans.MSF.List
-  ( module Control.Monad.Trans.MSF.List
-  , module Control.Monad.Trans.List
-  ) where
+    {-# WARNING "This module uses the ListT transformer, which is considered deprecated." #-}
+    ( module Control.Monad.Trans.MSF.List
+    , module Control.Monad.Trans.List
+    )
+  where
 
--- External
+-- External imports
 #if !MIN_VERSION_base(4,8,0)
 import Control.Applicative ((<$>))
 #endif
 
 import Control.Monad.Trans.List hiding (liftCallCC, liftCatch)
 
--- Internal
-import Data.MonadicStreamFunction
+-- Internal imports
 import Data.MonadicStreamFunction.InternalCore (MSF (MSF, unMSF))
 
 -- * List monad
 
--- Name alternative (in the article): collect
+-- | 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 msf = widthFirst' [msf]
+  where
     widthFirst' msfs = MSF $ \a -> do
-        (bs, msfs') <- unzip . concat <$> mapM (runListT . flip unMSF a) msfs
-        return (bs, widthFirst' msfs')
-
+      (bs, msfs') <- unzip . concat <$> mapM (runListT . flip unMSF a) msfs
+      return (bs, widthFirst' msfs')
 
--- Name alternatives: "choose", "parallely" (problematic because it's not multicore)
+-- | 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 -> ListT $ sequence $ apply a <$> msfs
   where
     apply a msf = do
-        (b, msf') <- unMSF msf a
-        return (b, sequenceS [msf'])
--- sequenceS = foldl (<+>) arrowzero . map liftMSFTrans
+      (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]
diff --git a/src/Control/Monad/Trans/MSF/Maybe.hs b/src/Control/Monad/Trans/MSF/Maybe.hs
--- a/src/Control/Monad/Trans/MSF/Maybe.hs
+++ b/src/Control/Monad/Trans/MSF/Maybe.hs
@@ -1,5 +1,4 @@
-{-# LANGUAGE Arrows     #-}
-{-# LANGUAGE Rank2Types #-}
+{-# LANGUAGE Arrows #-}
 -- |
 -- Copyright  : (c) Ivan Perez and Manuel Baerenz, 2016
 -- License    : BSD3
@@ -9,18 +8,23 @@
 -- for absent values, and for (nondescript) exceptions. The latter viewpoint
 -- is most natural in the context of 'MSF's.
 module Control.Monad.Trans.MSF.Maybe
-  ( module Control.Monad.Trans.MSF.Maybe
-  , module Control.Monad.Trans.Maybe
-  , maybeToExceptS
-  ) where
+    ( module Control.Monad.Trans.MSF.Maybe
+    , module Control.Monad.Trans.Maybe
+    , maybeToExceptS
+    )
+  where
 
--- External
+-- External imports
+import Control.Arrow             (returnA, (>>>), arr)
 import Control.Monad.Trans.Maybe hiding (liftCallCC, liftCatch, liftListen,
                                   liftPass)
 
--- Internal
-import Control.Monad.Trans.MSF.Except
-import Data.MonadicStreamFunction
+-- Internal imports
+import Control.Monad.Trans.MSF.Except (ExceptT, exceptS, listToMSFExcept,
+                                       maybeToExceptS, reactimateExcept,
+                                       runExceptT, runMSFExcept, safe, safely,
+                                       try)
+import Data.MonadicStreamFunction     (MSF, arrM, constM, liftTransS, morphS)
 
 -- * Throwing 'Nothing' as an exception ("exiting")
 
@@ -48,20 +52,22 @@
 inMaybeT :: Monad m => MSF (MaybeT m) (Maybe a) a
 inMaybeT = arrM $ MaybeT . return
 
-
 -- * Catching Maybe exceptions
 
--- | Run the first @msf@ until the second one produces 'True' from the output of the first.
+-- | Run the first @msf@ until the second one produces 'True' from the output
+-- of the first.
 untilMaybe :: Monad m => MSF m a b -> MSF m b Bool -> MSF (MaybeT m) a b
 untilMaybe msf cond = proc a -> do
   b <- liftTransS msf  -< a
   c <- liftTransS cond -< b
   inMaybeT -< if c then Nothing else Just b
 
--- | When an exception occurs in the first 'msf', the second 'msf' is executed from there.
-catchMaybe
-  :: (Functor m, Monad m)
-  => MSF (MaybeT m) a b -> MSF m a b -> MSF m a b
+-- | When an exception occurs in the first 'msf', the second 'msf' is executed
+-- from there.
+catchMaybe :: (Functor m, Monad m)
+           => MSF (MaybeT m) a b
+           -> MSF m a b
+           -> MSF m a b
 catchMaybe msf1 msf2 = safely $ do
   _ <- try $ maybeToExceptS msf1
   safe msf2
@@ -69,33 +75,35 @@
 -- * Converting to and from 'MaybeT'
 
 -- | Convert exceptions into `Nothing`, discarding the exception value.
-exceptToMaybeS :: (Functor m, Monad m) => MSF (ExceptT e m) a b -> MSF (MaybeT m) a b
-exceptToMaybeS = morphS $ MaybeT . fmap (either (const Nothing) Just) . runExceptT
+exceptToMaybeS :: (Functor m, Monad m)
+               => MSF (ExceptT e m) a b
+               -> MSF (MaybeT m) a b
+exceptToMaybeS =
+  morphS $ MaybeT . fmap (either (const Nothing) Just) . runExceptT
 
--- | Converts a list to an 'MSF' in 'MaybeT',
---   which outputs an element of the list at each step,
---   throwing 'Nothing' when the list ends.
+-- | Converts a list to an 'MSF' in 'MaybeT', which outputs an element of the
+-- list at each step, throwing 'Nothing' when the list ends.
 listToMaybeS :: (Functor m, Monad m) => [b] -> MSF (MaybeT m) a b
 listToMaybeS = exceptToMaybeS . runMSFExcept . listToMSFExcept
 
 -- * Running 'MaybeT'
--- | Remove the 'MaybeT' layer by outputting 'Nothing' when the exception occurs.
---   The continuation in which the exception occurred is then tested on the next input.
+
+-- | Remove the 'MaybeT' layer by outputting 'Nothing' when the exception
+-- occurs. The continuation in which the exception occurred is then tested on
+-- the next input.
 runMaybeS :: (Functor m, Monad m) => MSF (MaybeT m) a b -> MSF m a (Maybe b)
 runMaybeS msf = exceptS (maybeToExceptS msf) >>> arr eitherToMaybe
   where
     eitherToMaybe (Left ()) = Nothing
     eitherToMaybe (Right b) = Just b
 
-
 -- | Reactimates an 'MSF' in the 'MaybeT' monad until it throws 'Nothing'.
-reactimateMaybe
-  :: (Functor m, Monad m)
-  => MSF (MaybeT m) () () -> m ()
+reactimateMaybe :: (Functor m, Monad m)
+                => MSF (MaybeT m) () ()
+                -> m ()
 reactimateMaybe msf = reactimateExcept $ try $ maybeToExceptS msf
 
 -- | Run an 'MSF' fed from a list, discarding results. Useful when one needs to
 -- combine effects and streams (i.e., for testing purposes).
 embed_ :: (Functor m, Monad m) => MSF m a () -> [a] -> m ()
-
 embed_ msf as = reactimateMaybe $ listToMaybeS as >>> liftTransS msf
diff --git a/src/Control/Monad/Trans/MSF/RWS.hs b/src/Control/Monad/Trans/MSF/RWS.hs
--- a/src/Control/Monad/Trans/MSF/RWS.hs
+++ b/src/Control/Monad/Trans/MSF/RWS.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE CPP #-}
 -- |
 -- Copyright  : (c) Ivan Perez and Manuel Baerenz, 2016
 -- License    : BSD3
@@ -11,20 +12,23 @@
 -- has to be included, i.e. 'Control.Monad.RWS.Strict' instead of
 -- 'Control.Monad.RWS' or 'Control.Monad.RWS.Lazy'.
 module Control.Monad.Trans.MSF.RWS
-  ( module Control.Monad.Trans.MSF.RWS
-  , module Control.Monad.Trans.RWS.Strict
-  ) where
+    ( module Control.Monad.Trans.MSF.RWS
+    , module Control.Monad.Trans.RWS.Strict
+    )
+  where
 
--- External
+-- External imports
 import Control.Monad.Trans.RWS.Strict hiding (liftCallCC, liftCatch)
-import Data.Functor                   ((<$>))
-import Data.Monoid
 
--- Internal
-import Data.MonadicStreamFunction
+#if !MIN_VERSION_base(4,8,0)
+import Data.Functor ((<$>))
+import Data.Monoid  (Monoid)
+#endif
 
--- * 'RWS' (Reader-Writer-State) monad
+-- Internal imports
+import Data.MonadicStreamFunction (MSF, morphGS)
 
+-- * 'RWS' (Reader-Writer-State) monad
 
 -- | Wrap an 'MSF' with explicit state variables in 'RWST' monad.
 rwsS :: (Functor m, Monad m, Monoid w)
diff --git a/src/Control/Monad/Trans/MSF/Random.hs b/src/Control/Monad/Trans/MSF/Random.hs
--- a/src/Control/Monad/Trans/MSF/Random.hs
+++ b/src/Control/Monad/Trans/MSF/Random.hs
@@ -11,38 +11,37 @@
 -- Under the hood, 'RandT' is basically just 'StateT', with the current random
 -- number generator as mutable state.
 module Control.Monad.Trans.MSF.Random
-  (
-    runRandS
-  , evalRandS
-
-  , getRandomS
-  , getRandomsS
-  , getRandomRS
-  , getRandomRS_
-  , getRandomsRS
-  , getRandomsRS_
-  ) where
+    ( runRandS
+    , evalRandS
+    , getRandomS
+    , getRandomsS
+    , getRandomRS
+    , getRandomRS_
+    , getRandomsRS
+    , getRandomsRS_
+    )
+  where
 
--- External
-import Control.Monad.Random
+-- External imports
+import Control.Arrow        (arr, (>>>))
+import Control.Monad.Random (MonadRandom, RandT, Random, RandomGen, getRandom,
+                             getRandomR, getRandomRs, getRandoms, runRandT)
 
--- Internal
-import Control.Monad.Trans.MSF.State
-import Data.MonadicStreamFunction
+-- Internal imports
+import Control.Monad.Trans.MSF.State (StateT (..), runStateS_)
+import Data.MonadicStreamFunction    (MSF, arrM, constM, morphS)
 
--- | Run an 'MSF' in the 'RandT' random number monad transformer
---   by supplying an initial random generator.
---   Updates the generator every step.
+-- | Run an 'MSF' in the 'RandT' random number monad transformer by supplying
+-- an initial random generator. Updates the generator every step.
 runRandS :: (RandomGen g, Functor m, Monad m)
          => MSF (RandT g m) a b
          -> g -- ^ The initial random number generator.
          -> MSF m a (g, b)
 runRandS = runStateS_ . morphS (StateT . runRandT)
 
--- | Evaluate an 'MSF' in the 'RandT' transformer,
---   i.e. extract possibly random values
---   by supplying an initial random generator.
---   Updates the generator every step but discharges the generator.
+-- | Evaluate an 'MSF' in the 'RandT' transformer, i.e. extract possibly random
+-- values by supplying an initial random generator. Updates the generator every
+-- step but discharges the generator.
 evalRandS :: (RandomGen g, Functor m, Monad m)
           => MSF (RandT g m) a b -> g -> MSF m a b
 evalRandS msf g = runRandS msf g >>> arr snd
@@ -51,7 +50,6 @@
 getRandomS :: (MonadRandom m, Random b) => MSF m a b
 getRandomS = constM getRandom
 
-
 -- | Create a stream of lists of random values.
 getRandomsS :: (MonadRandom m, Random b) => MSF m a [b]
 getRandomsS = constM getRandoms
@@ -60,8 +58,8 @@
 getRandomRS :: (MonadRandom m, Random b) => (b, b) -> MSF m a b
 getRandomRS range = constM $ getRandomR range
 
--- | Create a stream of random values in a given range,
---   where the range is specified on every tick.
+-- | Create a stream of random values in a given range, where the range is
+-- specified on every tick.
 getRandomRS_ :: (MonadRandom m, Random b) => MSF m (b, b) b
 getRandomRS_  = arrM getRandomR
 
@@ -69,7 +67,7 @@
 getRandomsRS :: (MonadRandom m, Random b) => (b, b) -> MSF m a [b]
 getRandomsRS range = constM $ getRandomRs range
 
--- | Create a stream of lists of random values in a given range,
---   where the range is specified on every tick.
+-- | Create a stream of lists of random values in a given range, where the
+-- range is specified on every tick.
 getRandomsRS_ :: (MonadRandom m, Random b) => MSF m (b, b) [b]
 getRandomsRS_ = arrM getRandomRs
diff --git a/src/Control/Monad/Trans/MSF/Reader.hs b/src/Control/Monad/Trans/MSF/Reader.hs
--- a/src/Control/Monad/Trans/MSF/Reader.hs
+++ b/src/Control/Monad/Trans/MSF/Reader.hs
@@ -1,4 +1,3 @@
-{-# LANGUAGE Rank2Types #-}
 -- |
 -- Copyright  : (c) Ivan Perez and Manuel Baerenz, 2016
 -- License    : BSD3
@@ -11,18 +10,20 @@
 -- additional layer, and functions to flatten that layer out of the 'MSF`'s
 -- transformer stack.
 module Control.Monad.Trans.MSF.Reader
-  ( module Control.Monad.Trans.Reader
-  -- * 'Reader' 'MSF' running and wrapping.
-  , readerS
-  , runReaderS
-  , runReaderS_
-  ) where
+    ( module Control.Monad.Trans.Reader
+    -- * 'Reader' 'MSF' running and wrapping.
+    , readerS
+    , runReaderS
+    , runReaderS_
+    )
+  where
 
--- External
+-- External imports
+import Control.Arrow              (arr, (>>>))
 import Control.Monad.Trans.Reader hiding (liftCallCC, liftCatch)
 
--- Internal
-import Data.MonadicStreamFunction
+-- Internal imports
+import Data.MonadicStreamFunction (MSF, morphGS)
 
 -- * Reader 'MSF' running and wrapping
 
@@ -36,8 +37,7 @@
 runReaderS :: Monad m => MSF (ReaderT r m) a b -> MSF m (r, a) b
 runReaderS = morphGS $ \f (r, a) -> runReaderT (f a) r
 
-
 -- | Build an 'MSF' /function/ that takes a fixed environment as additional
 -- input, from an MSF in the 'Reader' monad.
 runReaderS_ :: Monad m => MSF (ReaderT s m) a b -> s -> MSF m a b
-runReaderS_ msf s = arr (\a -> (s,a)) >>> runReaderS msf
+runReaderS_ msf s = arr (\a -> (s, a)) >>> runReaderS msf
diff --git a/src/Control/Monad/Trans/MSF/State.hs b/src/Control/Monad/Trans/MSF/State.hs
--- a/src/Control/Monad/Trans/MSF/State.hs
+++ b/src/Control/Monad/Trans/MSF/State.hs
@@ -1,4 +1,4 @@
-{-# LANGUAGE Rank2Types #-}
+{-# LANGUAGE CPP #-}
 -- |
 -- Copyright  : (c) Ivan Perez and Manuel Baerenz, 2016
 -- License    : BSD3
@@ -16,23 +16,27 @@
 -- the strict version has to be included, i.e. 'Control.Monad.State.Strict'
 -- instead of 'Control.Monad.State' or 'Control.Monad.State.Lazy'.
 module Control.Monad.Trans.MSF.State
-  ( module Control.Monad.Trans.State.Strict
-  -- * 'State' 'MSF' running and wrapping
-  , stateS
-  , runStateS
-  , runStateS_
-  , runStateS__
-  ) where
+    ( module Control.Monad.Trans.State.Strict
+    -- * 'State' 'MSF' running and wrapping
+    , stateS
+    , runStateS
+    , runStateS_
+    , runStateS__
+    )
+  where
 
--- External
-import Control.Applicative
+-- External imports
+#if !MIN_VERSION_base(4,8,0)
+import Control.Applicative ((<$>))
+#endif
+
+import Control.Arrow                    (arr, (>>>))
 import Control.Monad.Trans.State.Strict hiding (liftCallCC, liftCatch,
                                          liftListen, liftPass)
 import Data.Tuple                       (swap)
 
--- Internal
-import Data.MonadicStreamFunction.Core
-import Data.MonadicStreamFunction.InternalCore
+-- Internal imports
+import Data.MonadicStreamFunction.Core (MSF, morphGS, feedback)
 
 -- * 'State' 'MSF' running and wrapping
 
@@ -51,12 +55,15 @@
 -- | Build an 'MSF' /function/ that takes a fixed state as additional input,
 -- from an 'MSF' in the 'State' monad, and outputs the new state with every
 -- transformation step.
-runStateS_ :: (Functor m, Monad m) => MSF (StateT s m) a b -> s -> MSF m a (s, b)
-runStateS_ msf s = feedback s
-                 $ arr swap >>> runStateS msf >>> arr (\(s', b) -> ((s', b), s'))
+runStateS_ :: (Functor m, Monad m)
+           => MSF (StateT s m) a b
+           -> s
+           -> MSF m a (s, b)
+runStateS_ msf s =
+  feedback s $
+    arr swap >>> runStateS msf >>> arr (\(s', b) -> ((s', b), s'))
 
--- TODO Rename this to execStateS!
--- | Build an 'MSF' /function/ that takes a fixed state as additional
--- input, from an 'MSF' in the 'State' monad.
+-- | Build an 'MSF' /function/ that takes a fixed state as additional input,
+-- from an 'MSF' in the 'State' monad.
 runStateS__ :: (Functor m, Monad m) => MSF (StateT s m) a b -> s -> MSF m a b
 runStateS__ msf s = runStateS_ msf s >>> arr snd
diff --git a/src/Control/Monad/Trans/MSF/Writer.hs b/src/Control/Monad/Trans/MSF/Writer.hs
--- a/src/Control/Monad/Trans/MSF/Writer.hs
+++ b/src/Control/Monad/Trans/MSF/Writer.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE CPP #-}
 -- |
 -- Copyright  : (c) Ivan Perez and Manuel Baerenz, 2016
 -- License    : BSD3
@@ -15,19 +16,23 @@
 -- the strict version has to be included, i.e. 'Control.Monad.Writer.Strict'
 -- instead of 'Control.Monad.Writer' or 'Control.Monad.Writer.Lazy'.
 module Control.Monad.Trans.MSF.Writer
-  ( module Control.Monad.Trans.Writer.Strict
-  -- * 'Writer' 'MSF' running and wrapping
-  , writerS
-  , runWriterS
-  ) where
+    ( module Control.Monad.Trans.Writer.Strict
+    -- * 'Writer' 'MSF' running and wrapping
+    , writerS
+    , runWriterS
+    )
+  where
 
--- External
+-- External imports
 import Control.Monad.Trans.Writer.Strict hiding (liftCallCC, liftCatch, pass)
-import Data.Functor                      ((<$>))
-import Data.Monoid
 
--- Internal
-import Data.MonadicStreamFunction
+#if !MIN_VERSION_base(4,8,0)
+import Data.Functor ((<$>))
+import Data.Monoid  (Monoid)
+#endif
+
+-- Internal imports
+import Data.MonadicStreamFunction (MSF, morphGS)
 
 -- * 'Writer' 'MSF' running and wrapping
 
diff --git a/src/Data/MonadicStreamFunction.hs b/src/Data/MonadicStreamFunction.hs
--- a/src/Data/MonadicStreamFunction.hs
+++ b/src/Data/MonadicStreamFunction.hs
@@ -47,14 +47,14 @@
   )
  where
 
--- External
+-- External imports
 import Control.Arrow
 
--- Internal
+-- Internal imports
 import Data.MonadicStreamFunction.Core
 import Data.MonadicStreamFunction.Util
 
--- Internal (Instances)
+-- Internal imports (instances)
 import Data.MonadicStreamFunction.Instances.ArrowChoice ()
 import Data.MonadicStreamFunction.Instances.ArrowLoop   ()
 import Data.MonadicStreamFunction.Instances.ArrowPlus   ()
diff --git a/src/Data/MonadicStreamFunction/Async.hs b/src/Data/MonadicStreamFunction/Async.hs
--- a/src/Data/MonadicStreamFunction/Async.hs
+++ b/src/Data/MonadicStreamFunction/Async.hs
@@ -7,9 +7,8 @@
 -- i.e. that change the speed at which data enters or leaves the 'MSF'.
 module Data.MonadicStreamFunction.Async where
 
--- Internal
-import Data.MonadicStreamFunction.Core
-import Data.MonadicStreamFunction.InternalCore
+-- Internal imports
+import Data.MonadicStreamFunction.InternalCore (MSF(MSF, unMSF))
 import Data.MonadicStreamFunction.Util         (MStream)
 
 -- |
@@ -21,7 +20,7 @@
 -- >>> let intstream = constS $ putStrLn "Enter a list of Ints:" >> readLn :: MStream IO [Int]
 -- >>> reactimate $ concatS intstream >>> arrM print
 -- Enter a list of Ints:
--- [1,2,33]
+-- [1, 2, 33]
 -- 1
 -- 2
 -- 33
@@ -30,14 +29,14 @@
 -- Enter a list of Ints:
 -- []
 -- Enter a list of Ints:
--- [1,2]
+-- [1, 2]
 -- 1
 -- 2
 -- Enter a list of Ints:
 -- ...
 --
--- Beware that @concatS msf@ becomes unproductive when @msf@ starts outputting empty lists forever.
--- This is ok:
+-- Beware that @concatS msf@ becomes unproductive when @msf@ starts outputting
+-- empty lists forever. This is ok:
 --
 -- >>> let boolToList b = if b then ["Yes"] else []
 -- >>> let everyOddEmpty = count >>> arr (even >>> boolToList)
@@ -64,6 +63,3 @@
     tick msf' []     = do
       (bs, msf'') <- unMSF msf' ()
       tick msf'' bs
--- TODO Maybe this can be written more nicely with exceptions?
--- Similarly takeS :: Int -> MSF m a b -> MSFExcept m a b () throws an exception after n ticks
--- Or with merge?
diff --git a/src/Data/MonadicStreamFunction/Core.hs b/src/Data/MonadicStreamFunction/Core.hs
--- a/src/Data/MonadicStreamFunction/Core.hs
+++ b/src/Data/MonadicStreamFunction/Core.hs
@@ -1,4 +1,10 @@
+{-# LANGUAGE CPP        #-}
 {-# LANGUAGE Rank2Types #-}
+-- We disable the following warning because this module purposefully defines
+-- orphan instances. This is a design decision in Dunai, so that we give
+-- implementors further flexibility while giving most users the features they
+-- expect.
+{-# OPTIONS_GHC -fno-warn-orphans #-}
 -- |
 -- Copyright  : (c) Ivan Perez and Manuel Baerenz, 2016
 -- License    : BSD3
@@ -56,51 +62,53 @@
     -- * Simulation
   , reactimate
   , embed
-  , module Control.Arrow
+  , module X
   )
   where
 
-import Control.Applicative
-import Control.Arrow
-import Control.Category          as C
-import Control.Monad.Base
-import Control.Monad.Trans.Class
-import Data.Tuple                (swap)
-import Prelude                   hiding (id, sum, (.))
+-- External imports
+import           Control.Arrow             (Arrow (..), (>>>))
+import qualified Control.Arrow             as X
+import           Control.Category          as C (id, (.))
+import           Control.Monad.Base        (MonadBase, liftBase)
+import           Control.Monad.Trans.Class (MonadTrans, lift)
+import           Prelude                   hiding (id, sum, (.))
 
-import Data.MonadicStreamFunction.InternalCore (MSF, embed, feedback, morphGS, reactimate)
+#if !MIN_VERSION_base(4,8,0)
+import Control.Applicative (Applicative(..))
+#endif
 
+-- Internal imports
+import Data.MonadicStreamFunction.InternalCore (MSF, embed, feedback, morphGS,
+                                                reactimate)
+
 -- * Definitions
 
 -- | 'Arrow' instance for 'MSF's.
 instance Monad m => Arrow (MSF m) where
-
   arr f = arrM (return . f)
 
-  -- first sf = MSF $ \(a,c) -> do
-  --   (b, sf') <- unMSF sf a
-  --   b `seq` return ((b, c), first sf')
-
-  first = morphGS $ \f (a,c) -> do
-            (b, msf') <- f a
-            return ((b, c), msf')
-
+  first =
+    -- This implementation is equivalent to:
+    -- first sf = MSF $ \(a, c) -> do
+    --   (b, sf') <- unMSF sf a
+    --   b `seq` return ((b, c), first sf')
+    morphGS $ \f (a, c) -> do
+      (b, msf') <- f a
+      return ((b, c), msf')
 
 -- * Functor and applicative instances
 
 -- | 'Functor' instance for 'MSF's.
 instance Monad m => Functor (MSF m a) where
   fmap f msf = msf >>> arr f
-  -- fmap f msf = MSF $ fmap fS . unMSF msf
-  --   where
-  --     fS (b, cont) = (f b, fmap f cont)
 
 -- | 'Applicative' instance for 'MSF's.
 instance (Functor m, Monad m) => Applicative (MSF m a) where
   -- It is possible to define this instance with only Applicative m
   pure = arr . const
-  fs <*> bs = (fs &&& bs) >>> arr (uncurry ($))
 
+  fs <*> bs = (fs &&& bs) >>> arr (uncurry ($))
 
 -- ** Lifting point-wise computations
 
@@ -112,11 +120,14 @@
 --
 -- Generalisation of 'arr' from 'Arrow' to monadic functions.
 arrM :: Monad m => (a -> m b) -> MSF m a b
---arrM f = go
---  where go = MSF $ \a -> do
---               b <- f a
---               return (b, go)
-arrM f = morphGS (\i a -> i a >>= \(_,c) -> f a >>= \b -> return (b, c)) C.id
+arrM f =
+  -- This implementation is equivalent to:
+  -- arrM f = go
+  --   where
+  --     go = MSF $ \a -> do
+  --            b <- f a
+  --            return (b, go)
+  morphGS (\i a -> i a >>= \(_, c) -> f a >>= \b -> return (b, c)) C.id
 
 -- | Monadic lifting from one monad into another
 liftBaseM :: (Monad m2, MonadBase m1 m2) => (a -> m1 b) -> MSF m2 a b
@@ -130,6 +141,7 @@
 liftBaseS = morphS liftBase
 
 -- *** MonadBase
+
 -- | Lift the first 'MSF' into the monad of the second.
 (^>>>) :: MonadBase m1 m2 => MSF m1 a b -> MSF m2 b c -> MSF m2 a c
 sf1 ^>>> sf2 = liftBaseS sf1 >>> sf2
@@ -143,7 +155,6 @@
 -- *** MonadTrans
 
 -- | Lift inner monadic actions in monad stacks.
-
 liftTransS :: (MonadTrans t, Monad m, Monad (t m))
            => MSF m a b
            -> MSF (t m) a b
@@ -156,9 +167,9 @@
 -- This is just a convenience function when you have a function to move across
 -- monads, because the signature of 'morphGS' is a bit complex.
 morphS :: (Monad m2, Monad m1)
-      => (forall c . m1 c -> m2 c)
-      -> MSF m1 a b
-      -> MSF m2 a b
+       => (forall c . m1 c -> m2 c)
+       -> MSF m1 a b
+       -> MSF m2 a b
 morphS morph = morphGS morph'
   where
     -- The following makes the a's and the b's the same, and it just says:
@@ -168,10 +179,11 @@
     -- Remember that:
     -- morphGS :: Monad m2
     --         => (forall c . (a1 -> m1 (b1, c)) -> (a2 -> m2 (b2, c)))
-    --           -- ^ The natural transformation. @mi@, @ai@ and @bi@ for @i = 1, 2@
-    --           --   can be chosen freely, but @c@ must be universally quantified
+    --           -- ^ The natural transformation. @mi@, @ai@ and @bi@ for
+    --           --   @i = 1, 2@ can be chosen freely, but @c@ must be
+    --           --   universally quantified
     --         -> MSF m1 a1 b1
     --         -> MSF m2 a2 b2
     --
     --  morph' :: (forall c . (a -> m1 (b, c)) -> (a -> m2 (b, c)))
-        morph' m1F = morph . m1F
+    morph' m1F = morph . m1F
diff --git a/src/Data/MonadicStreamFunction/Instances/ArrowChoice.hs b/src/Data/MonadicStreamFunction/Instances/ArrowChoice.hs
--- a/src/Data/MonadicStreamFunction/Instances/ArrowChoice.hs
+++ b/src/Data/MonadicStreamFunction/Instances/ArrowChoice.hs
@@ -10,10 +10,12 @@
 -- Import this module to include that (orphan) instance.
 module Data.MonadicStreamFunction.Instances.ArrowChoice where
 
-import Control.Arrow
+-- External imports
+import Control.Arrow (ArrowChoice (..))
 
-import Data.MonadicStreamFunction.Core
-import Data.MonadicStreamFunction.InternalCore
+-- Internal imports
+import Data.MonadicStreamFunction.Core         ()
+import Data.MonadicStreamFunction.InternalCore (MSF (MSF, unMSF))
 
 -- | 'ArrowChoice' instance for MSFs.
 instance Monad m => ArrowChoice (MSF m) where
diff --git a/src/Data/MonadicStreamFunction/Instances/ArrowLoop.hs b/src/Data/MonadicStreamFunction/Instances/ArrowLoop.hs
--- a/src/Data/MonadicStreamFunction/Instances/ArrowLoop.hs
+++ b/src/Data/MonadicStreamFunction/Instances/ArrowLoop.hs
@@ -13,17 +13,18 @@
 -- This is only defined for monads that are instances of 'MonadFix'.
 module Data.MonadicStreamFunction.Instances.ArrowLoop where
 
--- External
-import Control.Arrow
-import Control.Monad.Fix
+-- External imports
+import Control.Arrow     (ArrowLoop (..))
+import Control.Monad.Fix (MonadFix)
 
-import Data.MonadicStreamFunction.Core
-import Data.MonadicStreamFunction.InternalCore
+-- Internal imports
+import Data.MonadicStreamFunction.Core         ()
+import Data.MonadicStreamFunction.InternalCore (MSF (MSF, unMSF))
 
 -- | 'ArrowLoop' instance for MSFs. The monad must be an instance of
 -- 'MonadFix'.
 instance MonadFix m => ArrowLoop (MSF m) where
   loop :: MSF m (b, d) (c, d) -> MSF m b c
   loop sf = MSF $ \a -> do
-              rec ((b,c), sf') <- unMSF sf (a, c)
+              rec ((b, c), sf') <- unMSF sf (a, c)
               return (b, loop sf')
diff --git a/src/Data/MonadicStreamFunction/Instances/ArrowPlus.hs b/src/Data/MonadicStreamFunction/Instances/ArrowPlus.hs
--- a/src/Data/MonadicStreamFunction/Instances/ArrowPlus.hs
+++ b/src/Data/MonadicStreamFunction/Instances/ArrowPlus.hs
@@ -11,25 +11,27 @@
 -- This is only defined for monads that are instances of 'MonadPlus'.
 module Data.MonadicStreamFunction.Instances.ArrowPlus where
 
--- base
-import Control.Applicative
-import Control.Arrow
-import Control.Monad
+-- External imports
+import Control.Applicative (Alternative (..))
+import Control.Arrow       (ArrowPlus (..), ArrowZero (..))
+import Control.Monad       (MonadPlus, mplus, mzero)
 
--- dunai
-import Data.MonadicStreamFunction.Core
-import Data.MonadicStreamFunction.InternalCore
+-- Internal imports
+import Data.MonadicStreamFunction.Core         ()
+import Data.MonadicStreamFunction.InternalCore (MSF (MSF, unMSF))
 
--- | Instance of 'ArrowZero' for Monadic Stream Functions ('MSF').
---   The monad must be an instance of 'MonadPlus'.
+-- | Instance of 'ArrowZero' for Monadic Stream Functions ('MSF'). The monad
+-- must be an instance of 'MonadPlus'.
 instance (Monad m, MonadPlus m) => ArrowZero (MSF m) where
   zeroArrow = MSF $ const mzero
 
--- | Instance of 'ArrowPlus' for Monadic Stream Functions ('MSF').
---   The monad must be an instance of 'MonadPlus'.
+-- | Instance of 'ArrowPlus' for Monadic Stream Functions ('MSF'). The monad
+-- must be an instance of 'MonadPlus'.
 instance (Monad m, MonadPlus m) => ArrowPlus (MSF m) where
   sf1 <+> sf2 = MSF $ \a -> unMSF sf1 a `mplus` unMSF sf2 a
 
+-- | Instance of 'Alternative' for Monadic Stream Functions ('MSF'),
+-- implemented using the 'ArrowZero' and 'ArrowPlus' instances.
 instance (Functor m, Monad m, MonadPlus m) => Alternative (MSF m a) where
   empty = zeroArrow
   (<|>) = (<+>)
diff --git a/src/Data/MonadicStreamFunction/Instances/Num.hs b/src/Data/MonadicStreamFunction/Instances/Num.hs
--- a/src/Data/MonadicStreamFunction/Instances/Num.hs
+++ b/src/Data/MonadicStreamFunction/Instances/Num.hs
@@ -1,4 +1,3 @@
-{-# LANGUAGE TypeFamilies #-}
 {-# OPTIONS_GHC -fno-warn-orphans #-}
 -- |
 -- Copyright  : (c) Ivan Perez and Manuel Baerenz, 2016
@@ -22,12 +21,13 @@
 -- msf3 = (msf1 &&& msf2) >>> arr (uncurry (+))
 -- @
 --
--- Instances are provided for the type classes 'Num', 'Fractional'
--- and 'Floating'.
+-- Instances are provided for the type classes 'Num', 'Fractional' and
+-- 'Floating'.
 module Data.MonadicStreamFunction.Instances.Num where
 
-import Control.Arrow.Util
-import Data.MonadicStreamFunction.Core
+-- Internal imports
+import Control.Arrow.Util              (constantly, elementwise, elementwise2)
+import Data.MonadicStreamFunction.Core (MSF)
 
 -- | 'Num' instance for 'MSF's.
 instance (Monad m, Num b) => Num (MSF m a b) where
diff --git a/src/Data/MonadicStreamFunction/Instances/VectorSpace.hs b/src/Data/MonadicStreamFunction/Instances/VectorSpace.hs
--- a/src/Data/MonadicStreamFunction/Instances/VectorSpace.hs
+++ b/src/Data/MonadicStreamFunction/Instances/VectorSpace.hs
@@ -1,6 +1,5 @@
 {-# LANGUAGE FlexibleInstances     #-}
 {-# LANGUAGE MultiParamTypeClasses #-}
-{-# LANGUAGE TypeFamilies          #-}
 {-# LANGUAGE UndecidableInstances  #-}
 {-# OPTIONS_GHC -fno-warn-orphans #-}
 -- |
@@ -9,8 +8,8 @@
 -- Maintainer : ivan.perez@keera.co.uk
 --
 -- 'VectorSpace' instances for 'MSF's that produce vector spaces. This allows
--- you to use vector operators with 'MSF's that output vectors, for example, you
--- can write:
+-- you to use vector operators with 'MSF's that output vectors, for example,
+-- you can write:
 --
 -- @
 -- msf1 :: MSF Input (Double, Double) -- defined however you want
@@ -26,7 +25,7 @@
 -- @
 --
 --
--- Instances are provided for the type classes 'RModule' and 'VectorSpace'.
+-- Instances are provided for the type class 'VectorSpace'.
 
 -- Note: This module uses undecidable instances, because GHC does not know
 -- enough to assert that it will be able to determine the type of 's' from the
@@ -35,12 +34,13 @@
 -- resolved.
 module Data.MonadicStreamFunction.Instances.VectorSpace where
 
-import Control.Arrow
-import Data.VectorSpace
-
-import Control.Arrow.Util
+-- External imports
+import Control.Arrow    ((>>^))
+import Data.VectorSpace (VectorSpace (..))
 
-import Data.MonadicStreamFunction.Core
+-- Internal imports
+import Control.Arrow.Util              (constantly, elementwise2)
+import Data.MonadicStreamFunction.Core (MSF)
 
 -- | Vector-space instance for 'MSF's.
 instance (Monad m, VectorSpace v s) => VectorSpace (MSF m a v) s where
diff --git a/src/Data/MonadicStreamFunction/InternalCore.hs b/src/Data/MonadicStreamFunction/InternalCore.hs
--- a/src/Data/MonadicStreamFunction/InternalCore.hs
+++ b/src/Data/MonadicStreamFunction/InternalCore.hs
@@ -1,5 +1,4 @@
-{-# LANGUAGE ExplicitForAll #-}
-{-# LANGUAGE Rank2Types     #-}
+{-# LANGUAGE Rank2Types #-}
 -- |
 -- Copyright  : (c) Ivan Perez and Manuel Baerenz, 2016
 -- License    : BSD3
@@ -16,41 +15,38 @@
 -- 'MSF's are a generalisation of the implementation mechanism used by Yampa,
 -- Wormholes and other FRP and reactive implementations.
 --
--- This modules defines only the minimal core. Hopefully, other functions can
--- be defined in terms of the functions in this module without accessing the
--- MSF constuctor.
-
+-- This modules defines only the minimal core. By default, you should import
+-- "Data.MonadicStreamFunction.Core" or "Data.MonadicStreamFunction" whenever
+-- possible, and define your functions without accessing the MSF constuctor.
+-- Those modules, as well as other modules in dunai, also provide convenient
+-- instances. This module may be useful if you are extending dunai with
+-- functionality that cannot be (conveniently) expressed using the existing
+-- high-level API.
 
 -- NOTE TO IMPLEMENTORS:
 --
--- This module contains the core. Only the core. It should be possible
--- to define every function and type outside this module, except for the
--- instances for ArrowLoop, ArrowChoice, etc., without access to the
--- internal constructor for MSF and the function 'unMSF'.
+-- This module contains the core. Only the core. It should be possible to
+-- define every function and type outside this module, except for the instances
+-- for ArrowLoop, ArrowChoice, etc., without access to the internal constructor
+-- for MSF and the function 'unMSF'.
 --
--- It's very hard to know what IS essential to framework and if we start
--- adding all the functions and instances that *may* be useful in one
--- module.
+-- It's very hard to know what IS essential to framework and if we start adding
+-- all the functions and instances that *may* be useful in one module.
 --
--- By separating some instances and functions in other modules, we can
--- easily understand what is the essential idea and then analyse how it
--- is affected by an extension. It also helps demonstrate that something
--- works for MSFs + ArrowChoice, or MSFs + ArrowLoop, etc.
+-- By separating some instances and functions in other modules, we can easily
+-- understand what is the essential idea and then analyse how it is affected by
+-- an extension. It also helps demonstrate that something works for MSFs +
+-- ArrowChoice, or MSFs + ArrowLoop, etc.
 --
--- To address potential violations of basic design principles (like 'not
--- having orphan instances'), the main module Data.MonadicStreamFunction
--- exports everything. Users should *never* import this module here
--- individually, but the main module instead.
+-- To address potential violations of basic design principles (like 'not having
+-- orphan instances'), the main module Data.MonadicStreamFunction exports
+-- everything. Users should *never* import this module here individually, but
+-- the main module instead.
 module Data.MonadicStreamFunction.InternalCore where
 
--- External
-import Control.Applicative
-import Control.Arrow
-import Control.Category          (Category (..))
-import Control.Monad
-import Control.Monad.Base
-import Control.Monad.Trans.Class
-import Prelude                   hiding (id, sum, (.))
+-- External imports
+import Control.Category (Category (..))
+import Prelude          hiding (id, sum, (.))
 
 -- * Definitions
 
@@ -66,7 +62,9 @@
 -- | Instance definition for 'Category'. Defines 'id' and '.'.
 instance Monad m => Category (MSF m) where
   id = go
-    where go = MSF $ \a -> return (a, go)
+    where
+      go = MSF $ \a -> return (a, go)
+
   sf2 . sf1 = MSF $ \a -> do
     (b, sf1') <- unMSF sf1 a
     (c, sf2') <- unMSF sf2 b
@@ -81,17 +79,15 @@
 --
 -- __Mathematical background:__ The type @a -> m (b, c)@ is a functor in @c@,
 -- and @MSF m a b@ is its greatest fixpoint, i.e. it is isomorphic to the type
--- @a -> m (b, MSF m a b)@, by definition.
--- The types @m@, @a@ and @b@ are parameters of the functor.
--- Taking a fixpoint is functorial itself, meaning that a morphism
--- (a natural transformation) of two such functors gives a morphism
--- (an ordinary function) of their fixpoints.
+-- @a -> m (b, MSF m a b)@, by definition. The types @m@, @a@ and @b@ are
+-- parameters of the functor. Taking a fixpoint is functorial itself, meaning
+-- that a morphism (a natural transformation) of two such functors gives a
+-- morphism (an ordinary function) of their fixpoints.
 --
--- This is in a sense the most general "abstract" lifting function,
--- i.e. the most general one that only changes input, output and side effect
--- types, and doesn't influence control flow.
--- Other handling functions like exception handling or 'ListT' broadcasting
--- necessarily change control flow.
+-- This is in a sense the most general "abstract" lifting function, i.e. the
+-- most general one that only changes input, output and side effect types, and
+-- doesn't influence control flow. Other handling functions like exception
+-- handling or 'ListT' broadcasting necessarily change control flow.
 morphGS :: Monad m2
         => (forall c . (a1 -> m1 (b1, c)) -> (a2 -> m2 (b2, c)))
           -- ^ The natural transformation. @mi@, @ai@ and @bi@ for @i = 1, 2@
@@ -114,14 +110,14 @@
 
 -- | Apply a monadic stream function to a list.
 --
--- Because the result is in a monad, it may be necessary to
--- traverse the whole list to evaluate the value in the results to WHNF.
--- For example, if the monad is the maybe monad, this may not produce anything
--- if the 'MSF' produces 'Nothing' at any point, so the output stream cannot
--- consumed progressively.
+-- Because the result is in a monad, it may be necessary to traverse the whole
+-- list to evaluate the value in the results to WHNF.  For example, if the
+-- monad is the maybe monad, this may not produce anything if the 'MSF'
+-- produces 'Nothing' at any point, so the output stream cannot consumed
+-- progressively.
 --
--- To explore the output progressively, use 'arrM' and '(>>>)'', together
--- with some action that consumes/actuates on the output.
+-- To explore the output progressively, use 'arrM' and '(>>>)'', together with
+-- some action that consumes/actuates on the output.
 --
 -- This is called 'runSF' in Liu, Cheng, Hudak, "Causal Commutative Arrows and
 -- Their Optimization"
diff --git a/src/Data/MonadicStreamFunction/Parallel.hs b/src/Data/MonadicStreamFunction/Parallel.hs
--- a/src/Data/MonadicStreamFunction/Parallel.hs
+++ b/src/Data/MonadicStreamFunction/Parallel.hs
@@ -7,17 +7,16 @@
 -- possible.
 module Data.MonadicStreamFunction.Parallel where
 
--- External
-import Control.Arrow
-import GHC.Conc
-
--- Internal
-import Data.MonadicStreamFunction
-import Data.MonadicStreamFunction.InternalCore
+-- External imports
+import Control.Arrow (arr, (>>>))
+import GHC.Conc      (par, pseq)
 
--- | Run two 'MSF's in parallel, taking advantage of parallelism if
---   possible. This is the parallel version of '***'.
+-- Internal imports
+import Data.MonadicStreamFunction              ()
+import Data.MonadicStreamFunction.InternalCore (MSF (MSF, unMSF))
 
+-- | Run two 'MSF's in parallel, taking advantage of parallelism if possible.
+-- This is the parallel version of '***'.
 (*|*) :: Monad m => MSF m a b -> MSF m c d -> MSF m (a, c) (b, d)
 msf1 *|* msf2 = MSF $ \(a, c) -> do
   (b, msf1') <- unMSF msf1 a
diff --git a/src/Data/MonadicStreamFunction/ReactHandle.hs b/src/Data/MonadicStreamFunction/ReactHandle.hs
--- a/src/Data/MonadicStreamFunction/ReactHandle.hs
+++ b/src/Data/MonadicStreamFunction/ReactHandle.hs
@@ -5,30 +5,27 @@
 --
 -- 'ReactHandle's.
 --
--- Sometimes it is beneficial to give control to an external main loop,
--- for example OpenGL or a hardware-clocked audio server like JACK.
--- This module makes Dunai compatible with external main loops.
+-- Sometimes it is beneficial to give control to an external main loop, for
+-- example OpenGL or a hardware-clocked audio server like JACK. This module
+-- makes Dunai compatible with external main loops.
 module Data.MonadicStreamFunction.ReactHandle where
 
--- External
-import Control.Monad.IO.Class
-import Data.IORef
+-- External imports
+import Control.Monad.IO.Class (MonadIO, liftIO)
+import Data.IORef             (IORef, newIORef, readIORef, writeIORef)
 
--- Internal
-import Data.MonadicStreamFunction
-import Data.MonadicStreamFunction.InternalCore
+-- Internal imports
+import Data.MonadicStreamFunction              (MSF)
+import Data.MonadicStreamFunction.InternalCore (unMSF)
 
--- | A storage for the current state of an 'MSF'.
--- The 'MSF' may not require input or produce output data,
--- all such data must be handled through side effects
--- (such as wormholes).
+-- | A storage for the current state of an 'MSF'. The 'MSF' may not require
+-- input or produce output data, all such data must be handled through side
+-- effects (such as wormholes).
 type ReactHandle m = IORef (MSF m () ())
 
-
 -- | Needs to be called before the external main loop is dispatched.
 reactInit :: MonadIO m => MSF m () () -> m (ReactHandle m)
 reactInit = liftIO . newIORef
-
 
 -- | The callback that needs to be called by the external loop at every cycle.
 react :: MonadIO m => ReactHandle m -> m ()
diff --git a/src/Data/MonadicStreamFunction/Util.hs b/src/Data/MonadicStreamFunction/Util.hs
--- a/src/Data/MonadicStreamFunction/Util.hs
+++ b/src/Data/MonadicStreamFunction/Util.hs
@@ -1,5 +1,5 @@
-{-# LANGUAGE Arrows     #-}
-{-# LANGUAGE Rank2Types #-}
+{-# LANGUAGE Arrows #-}
+{-# LANGUAGE CPP    #-}
 -- |
 -- Copyright  : (c) Ivan Perez and Manuel Baerenz, 2016
 -- License    : BSD3
@@ -8,37 +8,33 @@
 -- Useful auxiliary functions and definitions.
 module Data.MonadicStreamFunction.Util where
 
--- External
-import Control.Arrow
-import Control.Category
-import Control.Monad
-import Control.Monad.Base
-import Data.Monoid
-import Data.VectorSpace
-import Prelude            hiding (id, (.))
+-- External imports
+import Control.Arrow    (arr, returnA, (&&&), (<<<), (>>>))
+import Control.Category (id, (.))
+import Control.Monad    (when)
+import Data.VectorSpace (VectorSpace, zeroVector, (^+^))
+import Prelude          hiding (id, (.))
 
--- Internal
-import Control.Monad.Trans.MSF.State
-import Data.MonadicStreamFunction.Core
+#if !MIN_VERSION_base(4,8,0)
+import Data.Monoid (Monoid, mempty, mappend)
+#endif
+
+-- Internal imports
+import Data.MonadicStreamFunction.Core                  (MSF, arrM, feedback)
 import Data.MonadicStreamFunction.Instances.ArrowChoice ()
 
 -- * Streams and sinks
 
--- | A stream is an 'MSF' that produces outputs, while ignoring the input.
--- It can obtain the values from a monadic context.
+-- | A stream is an 'MSF' that produces outputs, while ignoring the input. It
+-- can obtain the values from a monadic context.
 type MStream m a = MSF m () a
 
--- | A sink is an 'MSF' that consumes inputs, while producing no output.
--- It can consume the values with side effects.
-type MSink   m a = MSF m a ()
-
--- * Lifting
-
-
+-- | A sink is an 'MSF' that consumes inputs, while producing no output. It
+-- can consume the values with side effects.
+type MSink m a = MSF m a ()
 
 -- * Analogues of 'map' and 'fmap'
 
-
 -- | Apply an 'MSF' to every input. Freezes temporarily if the input is
 -- 'Nothing', and continues as soon as a 'Just' is received.
 mapMaybeS :: Monad m => MSF m a b -> MSF m (Maybe a) (Maybe b)
@@ -59,17 +55,13 @@
 
 -- * Delays
 
--- See also: 'iPre'
-
 -- | Delay a signal by one sample.
 iPre :: Monad m
      => a         -- ^ First output
      -> MSF m a a
--- iPre firsta = MSF $ \a -> return (firsta, iPre a)
 iPre firsta = feedback firsta $ arr swap
-  where swap (a,b) = (b, a)
--- iPre firsta = next firsta identity
-
+  where
+    swap (a, b) = (b, a)
 
 -- | Preprends a fixed output to an 'MSF'. The first input is completely
 -- ignored.
@@ -82,15 +74,20 @@
 next :: Monad m => b -> MSF m a b -> MSF m a b
 next b sf = sf >>> iPre b
 
--- | Buffers and returns the elements in FIFO order,
---   returning 'Nothing' whenever the buffer is empty.
+-- | Buffers and returns the elements in FIFO order, returning 'Nothing'
+-- whenever the buffer is empty.
 fifo :: Monad m => MSF m [a] (Maybe a)
-fifo = feedback [] $ proc (as, accum) -> do
-  let accum' = accum ++ as
-  returnA -< case accum' of
-    []       -> (Nothing, [])
-    (a : as) -> (Just a , as)
+fifo = feedback [] (arr (safeSnoc . uncurry fifoAppend))
+  where
+    -- | Append a new list to an accumulator in FIFO order.
+    fifoAppend :: [x] -> [x] -> [x]
+    fifoAppend as accum = accum ++ as
 
+    -- | Split a list into the head and the tail.
+    safeSnoc :: [x] -> (Maybe x, [x])
+    safeSnoc []     = (Nothing, [])
+    safeSnoc (x:xs) = (Just x, xs)
+
 -- * Folding
 
 -- ** Folding for 'VectorSpace' instances
@@ -120,16 +117,15 @@
 
 -- ** Generic folding \/ accumulation
 
--- | Applies a function to the input and an accumulator,
--- outputting the updated accumulator.
--- Equal to @\f s0 -> feedback s0 $ arr (uncurry f >>> dup)@.
+-- | Applies a function to the input and an accumulator, outputting the updated
+-- accumulator. Equal to @\f s0 -> feedback s0 $ arr (uncurry f >>> dup)@.
 accumulateWith :: Monad m => (a -> s -> s) -> s -> MSF m a s
 accumulateWith f s0 = feedback s0 $ arr g
   where
     g (a, s) = let s' = f a s in (s', s')
 
--- | Applies a transfer function to the input and an accumulator,
--- returning the updated accumulator and output.
+-- | Applies a transfer function to the input and an accumulator, returning the
+-- updated accumulator and output.
 mealy :: Monad m => (a -> s -> (b, s)) -> s -> MSF m a b
 mealy f s0 = feedback s0 $ arr $ uncurry f
 
@@ -141,14 +137,13 @@
 unfold f a = feedback a (arr (snd >>> f))
 
 -- | Generate outputs using a step-wise generation function and an initial
--- value. Version of 'unfold' in which the output and the new accumulator
--- are the same. Should be equal to @\f a -> unfold (f >>> dup) a@.
+-- value. Version of 'unfold' in which the output and the new accumulator are
+-- the same. Should be equal to @\f a -> unfold (f >>> dup) a@.
 repeatedly :: Monad m => (a -> a) -> a -> MSF m () a
 repeatedly f = unfold $ f >>> dup
   where
     dup a = (a, a)
 
-
 -- * Debugging
 
 -- | Outputs every input sample, with a given message prefix.
@@ -163,7 +158,11 @@
 
 -- | Outputs every input sample, with a given message prefix, using an
 -- auxiliary printing function, when a condition is met.
-traceWhen :: (Monad m, Show a) => (a -> Bool) -> (String -> m ()) -> String -> MSF m a a
+traceWhen :: (Monad m, Show a)
+          => (a -> Bool)
+          -> (String -> m ())
+          -> String
+          -> MSF m a a
 traceWhen cond method msg = withSideEffect $ \a ->
   when (cond a) $ method $ msg ++ show a
 
