diff --git a/CHANGELOG b/CHANGELOG
new file mode 100644
--- /dev/null
+++ b/CHANGELOG
@@ -0,0 +1,200 @@
+2026-10-21
+        * Version bump (0.14.2) (#475).
+        * Fix error in execution of `cabal update` in CI (#469).
+        * Constrain versions of `MonadRandom` for GHC < 8.0 (#470).
+        * Bump upper bounds on `hlint`, `time`, `transformers-compat` (#471).
+        * Change repository protocol in Cabal file to https (#473).
+
+2025-02-27
+        * Version bump (0.14.1) (#465).
+        * Change contact address (#462).
+        * Remove emails from CHANGELOG (#463).
+
+2024-12-21
+        * Version bump (0.14.0) (#460).
+        * Increase upper bounds on filepath, tasty, time, hlint (#448).
+        * Remove deprecated functions related to list-t (#445).
+
+2024-10-21
+        * Version bump (0.13.2) (#442).
+
+2024-08-21
+        * Version bump (0.13.1) (#430).
+        * Increase upper bounds on transformers (#427).
+        * Thanks to @tomsmeding.
+
+2024-06-21
+        * Version bump (0.13.0) (#420).
+        * Implement List interface using list-transformer (#418).
+
+2024-04-23
+        * Version bump (0.12.3) (#411).
+        * Fix typo in documentation (#410).
+
+2024-02-21
+        * Version bump (0.12.2) (#398).
+        * Limit version of transformers to < 0.6 (#405).
+
+2023-12-21
+        * Version bump (0.12.1) (#395).
+        * Remove postgresql repo before installation in CI script (#392).
+        * Add version bounds to dependencies (#393).
+        * Mark package as uncurated (#394).
+        * Fix typo in CHANGELOG (#396).
+
+2023-10-21
+        * Version bump (0.12.0) (#388).
+        * Increase max-backjumps in CI setup (#381).
+        * Document GHC 9.8.1 support in readme (#387).
+
+2023-08-21
+        * Version bump (0.11.2) (#377).
+        * Introduce benchmark (#375).
+
+2023-06-21
+        * Version bump (0.11.1) (#372).
+        * Reflect new contribution process in README (#362).
+
+2023-04-21
+        * Version bump (0.11.0) (#358).
+        * Update paper links to ACM, personal website (#346).
+
+2023-02-21
+        * Version bump (0.10.1) (#345).
+        * Enable FlexibleContexts in VectorSpace instance module (#344).
+
+2023-02-21
+        * Version bump (0.10.0) (#342).
+        * Implement dot in MSF's instance of VectorSpace (#298).
+        * Adjust version bounds for simple-affine-space (#343).
+
+2022-12-21
+        * Version bump (0.9.2) (#340).
+        * Bump version bounds for MonadRandom (#337).
+        * Adjust to work with simple-affine-space-0.2 (#339).
+
+2022-10-21
+        * Version bump (0.9.1) (#335).
+        * Add link to updated paper examples from README (#319).
+        * Update Travis script (#333).
+        * Style fixes (partial) (#334).
+
+2022-08-21
+        * Version bump (0.9.0) (#313).
+        * Document haskell-titan support in readme (#176).
+        * Re-format CHANGELOG for readability (#308).
+        * Add version bounds for dependencies (#303).
+        * Consistency in condition used to check GHC/base version (#295).
+        * Fix typo on documentation (#304).
+        * Document GHC 9.4.1 titan support in readme (#309).
+
+2022-06-21
+        * Version bump (0.8.3) (#302).
+        * 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).
+        * Re-structure README (#300).
+
+2022-04-21
+        * Version bump (0.8.2) (#280).
+        * Syntax rules (#271).
+        * Declare CHANGELOG (#273).
+        * Declare subdir of source-repository (#272).
+        * Fix haddock syntax error in documentation of switch (#274).
+        * Introduce new dSwitch function (#275).
+        * Syntax rules (#277).
+        * Remove unused module Ultrametric (#278).
+        * Remove unused module CausalCommutative (#279).
+
+2021-10-21
+        * Version bump (0.8.1).
+        * Code cleaning.
+        * Update example in README to new API.
+        * Fix broken link in README.
+        * Update badge in README.
+        * Fix typo in README.
+        * Thanks: @DireWolf707.
+
+2021-09-06
+        * Version bump (0.8.0).
+        * Code cleaning.
+        * List GHC 8.10 as supported in README.
+        * Thanks: @walseb, @turion, @bgluzman, @mezzomondo.
+
+2020-04-18
+        * Version bump (0.7.0).
+        * Add new utilities.
+        * Fix behaviour of listToMaybeS.
+        * List GHC 8.8 as supported in README.
+        * Cleaning and hlinting changes.
+        * Thanks: @turion, @Linearity.
+
+2020-01-25
+        * Version bump (0.6.0).
+        * Use simple-affine-space as dependency.
+        * Remove Data.VectorSpace.
+        * Fix error in documentation of embed.
+        * List GHC 8.6 as supported in README.
+        * Add links to videos to README.
+        * Fix typos in README.
+        * Thanks: @chriz-keera, @turion, @Rizary, @dynomite567,
+          @alexmarginean16.
+
+2019-09-29
+        * Version bump (0.5.2.1).
+        * Expose List support.
+        * Fix error in List on older versions of GHC.
+
+2019-09-29
+        * Version bump (0.5.2).
+        * Expose List support.
+        * Fix error in List support implementation.
+
+2018-11-03
+        * Version bump (0.5.1).
+        * Fix failed patterns in do notation.
+        * Thanks: @turion, @ggreif.
+
+2018-11-03
+        * Version bump (0.5).
+        * Rename lifting functions.
+        * Move definitions around.
+        * Thanks: @turion.
+
+2017-12-05
+        * Version bump (0.4).
+        * Add support for random numbers using MonadRandom.
+        * Remove MSF constructor from many definitions.
+        * Add support for older GHC versions.
+        * Move some definitions/modules around.
+        * Change licenses in examples, update them to use new API.
+        * Thanks: @thalerjonathan, @turion.
+
+2017-10-31
+        * Version bump (0.3).
+        * Add repo URL to cabal file.
+        * Add documentation to cabal file.
+        * Re-structure modules.
+        * Complete documentation in code.
+        * Add stack configuration file.
+        * Fix compilation errors with older versions of GHC.
+        * Update examples to use new API.
+
+Copyright (c) 2016, Ivan Perez and Manuel Bärenz.
+All rights reserved.
diff --git a/benchmarks/Bench.hs b/benchmarks/Bench.hs
new file mode 100644
--- /dev/null
+++ b/benchmarks/Bench.hs
@@ -0,0 +1,162 @@
+-- |
+-- Description : A benchmark for dunai.
+-- Copyright   : (c) Ivan Perez, 2023
+-- Authors     : Ivan Perez
+-- Maintainer  : ivan.perez@keera.co.uk
+-- License     : BSD3
+--
+-- A benchmark for Dunai.
+module Main where
+
+import Criterion             (bench, bgroup, nf)
+import Criterion.Main        (defaultConfig, defaultMainWith)
+import Criterion.Types       (Config (csvFile, resamples, verbosity),
+                              Verbosity (Quiet))
+import Data.Functor.Identity (runIdentity)
+import Data.Time.Format      (defaultTimeLocale, formatTime)
+import Data.Time.LocalTime   (getZonedTime)
+import System.Environment    (getArgs, withArgs)
+import System.FilePath       ((</>))
+
+import qualified Control.Category as C
+
+import Data.MonadicStreamFunction
+
+-- | Run all benchmarks.
+main :: IO ()
+main = do
+  config <- customConfig
+  withArgs [] $
+    defaultMainWith config
+       [ bgroup "basic"
+                [ bench "identity" $ nf basicIdentity 10000
+                , bench "id"       $ nf basicId       10000
+                ]
+       , bgroup "compositions"
+                [ bench "identity" $ nf composeIdentity 10000
+                , bench "idid"     $ nf composeIdId     10000
+                , bench "plus"     $ nf composePlus     10000
+                , bench "plusplus" $ nf composePlusPlus 10000
+                , bench "plusmult" $ nf composePlusMult 10000
+                , bench "mult"     $ nf composeMult     10000
+                , bench "multmult" $ nf composeMultMult 10000
+                ]
+       , bgroup "counter"
+                [ bench "counter1" $ nf counter1 10000
+                , bench "counter2" $ nf counter2 10000
+                ]
+       ]
+
+-- * Benchmarks
+
+-- ** Basic
+
+-- | Dunai's specialized identity function.
+basicIdentity :: Int -> [Int]
+basicIdentity n = runIdentity $ embed sf stream
+  where
+    sf     = C.id
+    stream = replicate n 1
+
+-- | Standard function identity lifted to SFs.
+basicId :: Int -> [Int]
+basicId n = runIdentity $ embed sf stream
+  where
+    sf     = arr id
+    stream = replicate n 1
+
+-- ** Compositions
+
+-- | Composition of Dunai's specialized identity function.
+composeIdentity :: Int -> [Int]
+composeIdentity n = runIdentity $ embed sf stream
+  where
+    sf     = C.id >>> C.id
+    stream = replicate n 1
+
+-- | Composition of standard function identity lifted to SFs.
+composeIdId :: Int -> [Int]
+composeIdId n = runIdentity $ embed sf stream
+  where
+    sf     = arr id >>> arr id
+    stream = replicate n 1
+
+-- | Plus operation.
+--
+-- This is not a composition; it merely exists to serve as a comparison with
+-- composePlusPlus.
+composePlus :: Int -> [Int]
+composePlus n = runIdentity $ embed sf stream
+  where
+    sf     = arr (+3)
+    stream = take n [1..]
+
+-- | Composition of addition lifted to SFs.
+composePlusPlus :: Int -> [Int]
+composePlusPlus n = runIdentity $ embed sf stream
+  where
+    sf     = arr (+1) >>> arr (+2)
+    stream = take n [1..]
+
+-- | Composition of addition with multiplication, lifted to SFs.
+composePlusMult :: Int -> [Int]
+composePlusMult n = runIdentity $ embed sf stream
+  where
+    sf     = arr (+100) >>> arr (*2)
+    stream = take n [10..]
+
+-- | Multiplication operation.
+--
+-- This is not a composition; it merely exists to serve as a comparison with
+-- composeMultMult.
+composeMult :: Int -> [Int]
+composeMult n = runIdentity $ embed sf stream
+  where
+    sf     = arr (*20)
+    stream = take n [10..]
+
+-- | Composition of multiplication lifted to SFs.
+composeMultMult :: Int -> [Int]
+composeMultMult n = runIdentity $ embed sf stream
+  where
+    sf     = arr (*10) >>> arr (*2)
+    stream = take n [10..]
+
+-- ** Counter
+
+-- | Counter without explicit seq.
+counter1 :: Int -> [Int]
+counter1 n = runIdentity $ embed sf stream
+  where
+    sf     = feedback 0 (arr (dup . uncurry (+)))
+    stream = replicate n 1
+
+    dup x = (x, x)
+
+-- | Counter with explicit seq.
+counter2 :: Int -> [Int]
+counter2 n = runIdentity $ embed sf stream
+  where
+    sf     = feedback 0 (arr ((\x -> x `seq` (x, x)). uncurry (+)))
+    stream = replicate n 1
+
+-- * Auxiliary functions
+
+-- Construct a config with increased number of sampling
+-- and a custom name for the report.
+customConfig :: IO Config
+customConfig = do
+  args <- getArgs
+
+  let dir = case args of
+              []     -> "."
+              (x:xs) -> x
+
+  -- Custom filename using the current time
+  timeString <- (formatTime defaultTimeLocale "%F-%H%M%S") <$> getZonedTime
+  let filename = concat [ timeString, "-", "bench.csv" ]
+
+  return $ defaultConfig { csvFile   = Just $ dir </> filename
+                         , resamples = 100000
+                         , verbosity = Quiet
+                         }
diff --git a/dunai.cabal b/dunai.cabal
--- a/dunai.cabal
+++ b/dunai.cabal
@@ -1,14 +1,53 @@
-name:                dunai
-version:             0.7.0
-synopsis:            Generalised reactive framework supporting classic, arrowized and monadic FRP.
-homepage:            https://github.com/ivanperez-keera/dunai
+-- Copyright (c) 2016 - Ivan Perez and Manuel Bärenz - All rights reserved
+--
+-- Redistribution and use in source and binary forms, with or without
+-- modification, are permitted provided that the following conditions are met:
+--
+--     * Redistributions of source code must retain the above copyright
+--       notice, this list of conditions and the following disclaimer.
+--
+--     * Redistributions in binary form must reproduce the above
+--       copyright notice, this list of conditions and the following
+--       disclaimer in the documentation and/or other materials provided
+--       with the distribution.
+--
+--     * Neither the name of Ivan Perez and Manuel Bärenz nor the names of
+--       other contributors may be used to endorse or promote products derived
+--       from this software without specific prior written permission.
+--
+-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+-- "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+-- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+-- A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+-- OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+-- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+-- LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+-- DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+-- THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+-- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+-- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+cabal-version: >= 1.10
+build-type:    Simple
+
+name:          dunai
+version:       0.14.2
+author:        Ivan Perez, Manuel Bärenz
+maintainer:    contact@ivanperez.io
+homepage:      https://github.com/ivanperez-keera/dunai
+license:       BSD3
+license-file:  LICENSE
+copyright:     Copyright (c) 2016 - Ivan Perez and Manuel Bärenz
+category:      Reactivity, FRP
+synopsis:
+  Generalised reactive framework supporting classic, arrowized and monadic FRP.
 description:
   Dunai is a DSL for strongly-typed CPS-based composable transformations.
   .
   Dunai is based on a concept of Monadic Stream Functions (MSFs). MSFs are
-  transformations defined by a function @unMSF :: MSF m a b -> a -> m (b, MSF m a b)@
-  that executes one step of a simulation, and produces an output in a monadic
-  context, and a continuation to be used for future steps.
+  transformations defined by a function
+  @unMSF :: MSF m a b -> a -> m (b, MSF m a b)@ that executes one step of a
+  simulation, and produces an output in a monadic context, and a continuation
+  to be used for future steps.
   .
   MSFs are a generalisation of the implementation mechanism used by Yampa,
   Wormholes and other FRP and reactive implementations.
@@ -25,115 +64,185 @@
   with @ListT@ gives rise to parallelism with broadcasting.
   .
   MSFs can be used to implement many FRP variants, including Arrowized FRP,
-  Classic FRP, and plain reactive programming. Arrowized and applicative
-  syntax are both supported.
+  Classic FRP, and plain reactive programming. Arrowized and applicative syntax
+  are both supported.
   .
   For a very detailed introduction to MSFs, see:
   <http://dl.acm.org/citation.cfm?id=2976010>
-  (mirror: <http://www.cs.nott.ac.uk/~psxip1/#FRPRefactored>).
-license:             BSD3
-license-file:        LICENSE
-author:              Ivan Perez, Manuel Bärenz
-maintainer:          ivan.perez@keera.co.uk
--- copyright:
-category:            Reactivity, FRP
-build-type:          Simple
--- extra-source-files:
-cabal-version:       >=1.10
+  (mirror: <http://ivanperez.io/#FRPRefactored>).
 
+
+x-curation: uncurated
+
+
+extra-source-files:
+  CHANGELOG
+
+
+source-repository head
+  type:     git
+  location: https://github.com/ivanperez-keera/dunai.git
+  subdir:   dunai
+
+
 -- You can disable the hlint test suite with -f-test-hlint
 flag test-hlint
   description: Enable hlint test suite
-  default: False
-  manual: True
+  default:     False
+  manual:      True
 
 -- You can disable the haddock coverage test suite with -f-test-doc-coverage
 flag test-doc-coverage
   description: Enable haddock coverage test suite
-  default: False
-  manual: True
+  default:     False
+  manual:      True
 
+
 library
-  exposed-modules:   Control.Monad.Trans.MSF
-                     Control.Monad.Trans.MSF.Except
-                     Control.Monad.Trans.MSF.Maybe
-                     Control.Monad.Trans.MSF.List
-                     Control.Monad.Trans.MSF.Random
-                     Control.Monad.Trans.MSF.Reader
-                     Control.Monad.Trans.MSF.RWS
-                     Control.Monad.Trans.MSF.State
-                     Control.Monad.Trans.MSF.Writer
-                     Data.MonadicStreamFunction
-                     Data.MonadicStreamFunction.Core
-                     Data.MonadicStreamFunction.Async
-                     Data.MonadicStreamFunction.Instances.ArrowChoice
-                     Data.MonadicStreamFunction.Instances.ArrowLoop
-                     Data.MonadicStreamFunction.Instances.ArrowPlus
-                     Data.MonadicStreamFunction.Instances.Num
-                     Data.MonadicStreamFunction.Instances.VectorSpace
-                     Data.MonadicStreamFunction.InternalCore
-                     Data.MonadicStreamFunction.Parallel
-                     Data.MonadicStreamFunction.ReactHandle
-                     Data.MonadicStreamFunction.Util
+  exposed-modules:
+    Control.Monad.Trans.MSF
+    Control.Monad.Trans.MSF.Except
+    Control.Monad.Trans.MSF.List
+    Control.Monad.Trans.MSF.Maybe
+    Control.Monad.Trans.MSF.Random
+    Control.Monad.Trans.MSF.Reader
+    Control.Monad.Trans.MSF.RWS
+    Control.Monad.Trans.MSF.State
+    Control.Monad.Trans.MSF.Writer
+    Data.MonadicStreamFunction
+    Data.MonadicStreamFunction.Async
+    Data.MonadicStreamFunction.Core
+    Data.MonadicStreamFunction.Instances.ArrowChoice
+    Data.MonadicStreamFunction.Instances.ArrowLoop
+    Data.MonadicStreamFunction.Instances.ArrowPlus
+    Data.MonadicStreamFunction.Instances.Num
+    Data.MonadicStreamFunction.Instances.VectorSpace
+    Data.MonadicStreamFunction.InternalCore
+    Data.MonadicStreamFunction.Parallel
+    Data.MonadicStreamFunction.ReactHandle
+    Data.MonadicStreamFunction.Util
 
-  other-modules:     Control.Arrow.Util
+  other-modules:
+    Control.Arrow.Util
 
-  build-depends:     base >=4.6 && < 5,
-                     transformers,
-                     transformers-base,
-                     MonadRandom,
-                     simple-affine-space
+  build-depends:
+      base >= 4.6 && < 5
+    , MonadRandom         >= 0.2   && < 0.7
+    , list-transformer    >= 1.1.1 && < 1.2
+    , simple-affine-space >= 0.2   && < 0.3
+    , transformers        >= 0.3   && < 0.7
+    , transformers-base   >= 0.4   && < 0.5
 
-  hs-source-dirs:    src
-  default-language:  Haskell2010
-  ghc-options:       -Wall -fno-warn-unused-do-bind
+  default-language:
+    Haskell2010
 
+  hs-source-dirs:
+    src
+
+  ghc-options:
+    -Wall -fno-warn-unused-do-bind
+
   if impl(ghc <= 7.8.4)
-    build-depends: transformers-compat
+    build-depends:
+        MonadRandom         >= 0.2 && < 0.6
+      , transformers-compat >= 0.3 && < 0.9
+      , void                >= 0.1 && < 0.8
 
+  if impl(ghc < 8.0)
+    build-depends:
+     MonadRandom >= 0.2 && < 0.6.2.1
+
 test-suite hlint
-  type: exitcode-stdio-1.0
-  main-is: HLintMain.hs
-  hs-source-dirs: tests
-  default-language:  Haskell2010
+  type:
+    exitcode-stdio-1.0
+
+  main-is:
+    HLintMain.hs
+
+  default-language:
+    Haskell2010
+
+  hs-source-dirs:
+    tests
+
   if !flag(test-hlint)
-    buildable: False
+    buildable:
+      False
   else
     build-depends:
-      base,
-      hlint >= 1.7
+        base  >= 4   && < 5
+      , hlint >= 1.7 && < 3.11
 
 -- Verify that the code is thoroughly documented
 test-suite haddock-coverage
-  type: exitcode-stdio-1.0
-  main-is: HaddockCoverage.hs
-  ghc-options: -Wall
-  hs-source-dirs: tests
-  default-language:  Haskell2010
+  type:
+    exitcode-stdio-1.0
 
+  main-is:
+    HaddockCoverage.hs
+
+  default-language:
+    Haskell2010
+
+  hs-source-dirs:
+    tests
+
+  ghc-options:
+    -Wall
+
   if !flag(test-doc-coverage)
-    buildable: False
+    buildable:
+      False
   else
     build-depends:
-      base >= 4 && < 5,
-      directory,
-      filepath,
-      process,
-      regex-posix
+        base           >= 4       && < 5
+      , directory      >= 1.2     && < 1.4
+      , filepath       >= 1.3.0.1 && < 1.6
+      , process        >= 1.1.0.2 && < 1.7
+      , regex-posix    >= 0.95    && < 0.97
 
-source-repository head
-  type:     git
-  location: git@github.com:ivanperez-keera/dunai.git
 
 test-suite regression-tests
-  type: exitcode-stdio-1.0
-  main-is: RegressionTests.hs
-  ghc-options: -Wall
-  hs-source-dirs: tests
-  default-language:  Haskell2010
+  type:
+    exitcode-stdio-1.0
+
+  main-is:
+    RegressionTests.hs
+
+  default-language:
+    Haskell2010
+
+  hs-source-dirs:
+    tests
+
+  ghc-options:
+    -Wall
+
   build-depends:
-    base >=4 && <5,
-    transformers,
-    dunai,
-    tasty,
-    tasty-hunit
+      base         >= 4   && < 5
+    , transformers >= 0.3 && < 0.7
+    , tasty        >= 0.1 && < 1.6
+    , tasty-hunit  >= 0.8 && < 0.11
+
+    , dunai
+
+
+benchmark dunai-bench
+  type:
+    exitcode-stdio-1.0
+
+  main-is:
+    Bench.hs
+
+  build-depends:
+       base      >= 4       && < 5
+     , criterion >= 0.5.0.0 && < 1.7
+     , filepath  >= 1.3.0.1 && < 1.6
+     , time      >= 1.4     && < 1.17
+     , dunai
+
+  default-language:
+    Haskell2010
+
+  hs-source-dirs:
+    benchmarks
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
@@ -1,24 +1,21 @@
--- | Utility functions to work with 'Arrow's.
+-- |
+-- Copyright  : (c) Ivan Perez and Manuel Baerenz, 2016
+-- License    : BSD3
+-- Maintainer : ivan.perez@keera.co.uk
+--
+-- 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 #-}
 
--- import Control.Category (id)
--- import Prelude hiding (id)
-
--- (&&&!) :: Arrow a => a b c -> a b () -> a b c
--- a1 &&&! a2 = (a1 &&& a2) >>> arr fst
-
--- sink :: Arrow a => a b c -> a c () -> a b c
--- a1 `sink` a2 = a1 >>> (id &&& a2) >>> arr fst
+-- * 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,6 +1,9 @@
-{-# LANGUAGE Rank2Types #-}
-
--- | This module reexports nearly all submodules. RWS is not exported since
+-- |
+-- Copyright  : (c) Ivan Perez and Manuel Baerenz, 2016
+-- License    : BSD3
+-- Maintainer : ivan.perez@keera.co.uk
+--
+-- This module reexports nearly all submodules. RWS is not exported since
 -- names collide with Reader, State and Writer.
 module Control.Monad.Trans.MSF
     ( module Control.Monad.Trans.MSF.Except
@@ -12,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,32 +1,43 @@
-{-# LANGUAGE Arrows              #-}
-{-# LANGUAGE CPP                 #-}
-{-# LANGUAGE Rank2Types          #-}
-{-# LANGUAGE TupleSections       #-}
--- | 'MSF's in the 'ExceptT' monad are monadic stream functions
---   that can throw exceptions,
---   i.e. return an exception value instead of a continuation.
---   This module gives ways to throw exceptions in various ways,
---   and to handle them through a monadic interface.
+{-# LANGUAGE Arrows     #-}
+{-# LANGUAGE CPP        #-}
+{-# LANGUAGE Rank2Types #-}
+-- |
+-- Copyright  : (c) Ivan Perez and Manuel Baerenz, 2016
+-- License    : BSD3
+-- Maintainer : ivan.perez@keera.co.uk
+--
+-- 'MSF's in the 'ExceptT' monad are monadic stream functions that can throw
+-- exceptions, i.e. return an exception value instead of a continuation. This
+-- 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
+-- External imports
+#if !MIN_VERSION_base(4,8,0)
+import           Control.Applicative        (Applicative (..), (<$>))
+#endif
 
-import           Control.Applicative
+import           Control.Arrow              (arr, returnA, (<<<), (>>>))
 import qualified Control.Category           as Category
-import           Control.Monad              (liftM, ap)
-import           Control.Monad.Trans.Class
-import           Control.Monad.Trans.Except hiding (liftCallCC, liftListen, liftPass) -- Avoid conflicting exports
-import           Control.Monad.Trans.Maybe
+import           Control.Monad              (ap, liftM)
+import           Control.Monad.Trans.Class  (lift)
+import           Control.Monad.Trans.Except hiding (liftCallCC, liftListen,
+                                             liftPass)
+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
+#if !MIN_VERSION_base(4,10,0)
 fromLeft  :: a -> Either a b -> a
 fromLeft  _ (Left  a) = a
 fromLeft  a (Right _) = a
@@ -45,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
@@ -64,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
 
@@ -81,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
 
@@ -177,40 +184,36 @@
   return = pure
   MSFExcept msf >>= f = MSFExcept $ handleExceptT msf $ runMSFExcept . f
 
-handleExceptT
-  :: Monad m
-  => MSF (ExceptT e1 m) a b
-  -> (e1 -> MSF (ExceptT e2 m) a b)
-  -> MSF (ExceptT e2 m) a b
+-- | Execute an MSF and, if it throws an exception, recover by switching 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 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
 
@@ -218,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           -< ()
@@ -227,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
@@ -265,14 +261,35 @@
 reactimateB :: Monad m => MSF m () Bool -> m ()
 reactimateB sf = reactimateExcept $ try $ liftTransS sf >>> throwOn ()
 
--- * Analog to Yampa's switch, with Maybe instead of Event
+-- | 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),
+-- 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),
+-- 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
+  where
+    ef = feedback Nothing $ proc (a, me) -> do
+           throwMaybe    -< me
+           liftTransS sf -< a
+
 -- | More general lifting combinator that enables recovery. Note that, unlike a
 -- polymorphic lifting function @forall a . m a -> m1 a@, this auxiliary
 -- function needs to be a bit more structured, and produces a Maybe value. The
@@ -283,12 +300,16 @@
        -> 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))
           -> MSF m1 a b1
           -> 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,39 +1,68 @@
 {-# 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 Control.Monad.Trans.List
-  ) where
-
--- External
-import Control.Monad.Trans.List
-  hiding (liftCallCC, liftCatch) -- Avoid conflicting exports
+    ( module Control.Monad.Trans.MSF.List
+    , module List
+    )
+  where
 
+-- External imports
 #if !MIN_VERSION_base(4,8,0)
 import Control.Applicative ((<$>))
 #endif
 
--- Internal
-import Data.MonadicStreamFunction
+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
 
--- 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 (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
 
--- 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
+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'])
--- 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]
@@ -45,4 +74,3 @@
       (b, sf')   <- unMSF sf a
       (bs, sf'') <- consume sf' as
       b `seq` return (b:bs, sf'')
-
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,23 +1,30 @@
-{-# LANGUAGE Arrows              #-}
-{-# LANGUAGE Rank2Types          #-}
-{- |
-The 'Maybe' monad is very versatile. It can stand for default arguments,
-for absent values, and for (nondescript) exceptions.
-The latter viewpoint is most natural in the context of 'MSF's.
--}
+{-# LANGUAGE Arrows #-}
+-- |
+-- Copyright  : (c) Ivan Perez and Manuel Baerenz, 2016
+-- License    : BSD3
+-- Maintainer : ivan.perez@keera.co.uk
+--
+-- The 'Maybe' monad is very versatile. It can stand for default arguments,
+-- 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
-import Control.Monad.Trans.Maybe
-  hiding (liftCallCC, liftCatch, liftListen, liftPass) -- Avoid conflicting exports
+-- 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")
 
@@ -45,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
@@ -66,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,26 +1,34 @@
--- | This module combines the wrapping and running functions
---   for the 'Reader', 'Writer' and 'State' monad layers in a single layer.
+{-# LANGUAGE CPP #-}
+-- |
+-- Copyright  : (c) Ivan Perez and Manuel Baerenz, 2016
+-- License    : BSD3
+-- Maintainer : ivan.perez@keera.co.uk
 --
+-- This module combines the wrapping and running functions for the 'Reader',
+-- 'Writer' and 'State' monad layers in a single layer.
+--
 -- It is based on the _strict_ 'RWS' monad 'Control.Monad.Trans.RWS.Strict',
--- so when combining it with other modules such as @mtl@'s,
--- the strict version has to be included, i.e. 'Control.Monad.RWS.Strict'
--- instead of 'Control.Monad.RWS' or 'Control.Monad.RWS.Lazy'.
+-- so when combining it with other modules such as @mtl@'s, the strict version
+-- 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
-import Control.Monad.Trans.RWS.Strict
-  hiding (liftCallCC, liftCatch) -- Avoid conflicting exports
-import Data.Monoid
+-- External imports
+import Control.Monad.Trans.RWS.Strict hiding (liftCallCC, liftCatch)
+
+#if !MIN_VERSION_base(4,8,0)
 import Data.Functor ((<$>))
+import Data.Monoid  (Monoid)
+#endif
 
--- Internal
-import Data.MonadicStreamFunction
+-- 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
@@ -1,47 +1,47 @@
--- | In this module, 'MSF's in a monad supporting random number generation
---   (i.e. having the 'RandT' layer in its stack) can be run.
---   Running means supplying an initial random number generator,
---   where the update of the generator at every random number generation
---   is already taken care of.
+-- |
+-- Copyright  : (c) Ivan Perez and Manuel Baerenz, 2016
+-- License    : BSD3
+-- Maintainer : ivan.perez@keera.co.uk
 --
---   Under the hood, 'RandT' is basically just 'StateT',
---   with the current random number generator as mutable state.
-
-
-{-# LANGUAGE Arrows              #-}
+-- In this module, 'MSF's in a monad supporting random number generation (i.e.
+-- having the 'RandT' layer in its stack) can be run. Running means supplying
+-- an initial random number generator, where the update of the generator at
+-- every random number generation is already taken care of.
+--
+-- 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 Data.MonadicStreamFunction
-import Control.Monad.Trans.MSF.State
+-- 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
@@ -50,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
@@ -59,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
 
@@ -68,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,25 +1,29 @@
-{-# LANGUAGE Rank2Types          #-}
-
--- | 'MSF's with a 'Reader' monadic layer.
+-- |
+-- Copyright  : (c) Ivan Perez and Manuel Baerenz, 2016
+-- License    : BSD3
+-- Maintainer : ivan.perez@keera.co.uk
 --
+-- 'MSF's with a 'Reader' monadic layer.
+--
 -- This module contains functions to work with 'MSF's that include a 'Reader'
 -- monadic layer. This includes functions to create new 'MSF's that include an
 -- 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
-import Control.Monad.Trans.Reader
-  hiding (liftCallCC, liftCatch) -- Avoid conflicting exports
+-- 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
 
@@ -33,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,6 +1,11 @@
-{-# LANGUAGE Rank2Types #-}
--- | 'MSF's with a 'State' monadic layer.
+{-# LANGUAGE CPP #-}
+-- |
+-- Copyright  : (c) Ivan Perez and Manuel Baerenz, 2016
+-- License    : BSD3
+-- Maintainer : ivan.perez@keera.co.uk
 --
+-- 'MSF's with a 'State' monadic layer.
+--
 -- This module contains functions to work with 'MSF's that include a 'State'
 -- monadic layer. This includes functions to create new 'MSF's that include an
 -- additional layer, and functions to flatten that layer out of the 'MSF`'s
@@ -11,24 +16,28 @@
 -- 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
-import Control.Monad.Trans.State.Strict
-  hiding (liftCallCC, liftCatch, liftListen, liftPass) -- Avoid conflicting exports
-import Data.Tuple (swap)
+-- External imports
+#if !MIN_VERSION_base(4,8,0)
+import Control.Applicative ((<$>))
+#endif
 
--- Internal
-import Data.MonadicStreamFunction.Core
-import Data.MonadicStreamFunction.InternalCore
+import Control.Arrow                    (arr, (>>>))
+import Control.Monad.Trans.State.Strict hiding (liftCallCC, liftCatch,
+                                         liftListen, liftPass)
+import Data.Tuple                       (swap)
 
+-- Internal imports
+import Data.MonadicStreamFunction.Core (MSF, morphGS, feedback)
+
 -- * 'State' 'MSF' running and wrapping
 
 -- | Build an 'MSF' in the 'State' monad from one that takes the state as an
@@ -46,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,5 +1,11 @@
--- | 'MSF's with a 'Writer' monadic layer.
+{-# LANGUAGE CPP #-}
+-- |
+-- Copyright  : (c) Ivan Perez and Manuel Baerenz, 2016
+-- License    : BSD3
+-- Maintainer : ivan.perez@keera.co.uk
 --
+-- 'MSF's with a 'Writer' monadic layer.
+--
 -- This module contains functions to work with 'MSF's that include a 'Writer'
 -- monadic layer. This includes functions to create new 'MSF's that include an
 -- additional layer, and functions to flatten that layer out of the 'MSF`'s
@@ -10,20 +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
-import Control.Monad.Trans.Writer.Strict
-  hiding (liftCallCC, liftCatch, pass) -- Avoid conflicting exports
+-- External imports
+import Control.Monad.Trans.Writer.Strict hiding (liftCallCC, liftCatch, pass)
+
+#if !MIN_VERSION_base(4,8,0)
 import Data.Functor ((<$>))
-import Data.Monoid
+import Data.Monoid  (Monoid)
+#endif
 
--- Internal
-import Data.MonadicStreamFunction
+-- 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
@@ -1,41 +1,45 @@
--- | Monadic Stream Functions are synchronized stream functions
---   with side effects.
+-- |
+-- Copyright  : (c) Ivan Perez and Manuel Baerenz, 2016
+-- License    : BSD3
+-- Maintainer : ivan.perez@keera.co.uk
 --
---   'MSF's are defined by a function
---   @unMSF :: MSF m a b -> a -> m (b, MSF m a b)@
---   that executes one step of a simulation, and produces an output in a
---   monadic context, and a continuation to be used for future steps.
+-- Monadic Stream Functions are synchronized stream functions with side
+-- effects.
 --
---   See the module "Data.MonadicStreamFunction.Core" for details.
+-- 'MSF's are defined by a function
+-- @unMSF :: MSF m a b -> a -> m (b, MSF m a b)@
+-- that executes one step of a simulation, and produces an output in a monadic
+-- context, and a continuation to be used for future steps.
 --
---   'MSF's are a generalisation of the implementation mechanism used by Yampa,
---   Wormholes and other FRP and reactive implementations.
+-- See the module "Data.MonadicStreamFunction.Core" for details.
 --
---   When combined with different monads, they produce interesting effects. For
---   example, when combined with the 'Maybe' monad, they become transformations
---   that may stop producing outputs (and continuations). The 'Either' monad
---   gives rise to 'MSF's that end with a result (akin to Tasks in Yampa, and
---   Monadic FRP).
+-- 'MSF's are a generalisation of the implementation mechanism used by Yampa,
+-- Wormholes and other FRP and reactive implementations.
 --
---   Flattening, that is, going from some structure @MSF (t m) a b@ to @MSF m a b@
---   for a specific transformer @t@ often gives rise to known FRP constructs.
---   For instance, flattening with 'EitherT' gives rise to switching, and
---   flattening with 'ListT' gives rise to parallelism with broadcasting.
+-- When combined with different monads, they produce interesting effects. For
+-- example, when combined with the 'Maybe' monad, they become transformations
+-- that may stop producing outputs (and continuations). The 'Either' monad
+-- gives rise to 'MSF's that end with a result (akin to Tasks in Yampa, and
+-- Monadic FRP).
 --
---   'MSF's can be used to implement many FRP variants, including Arrowized FRP,
---   Classic FRP, and plain reactive programming. Arrowized and applicative
---   syntax are both supported.
+-- Flattening, that is, going from some structure @MSF (t m) a b@ to @MSF m a
+-- b@ for a specific transformer @t@ often gives rise to known FRP constructs.
+-- For instance, flattening with 'EitherT' gives rise to switching, and
+-- flattening with 'ListT' gives rise to parallelism with broadcasting.
 --
---   For a very detailed introduction to 'MSF's, see:
---   <http://dl.acm.org/citation.cfm?id=2976010>
---   (mirror: <http://www.cs.nott.ac.uk/~psxip1/#FRPRefactored>).
+-- 'MSF's can be used to implement many FRP variants, including Arrowized FRP,
+-- Classic FRP, and plain reactive programming. Arrowized and applicative
+-- syntax are both supported.
 --
---   Apart from the modules exported, this module exports instances from:
+-- For a very detailed introduction to 'MSF's, see:
+-- <http://dl.acm.org/citation.cfm?id=2976010>
+-- (mirror: <http://www.cs.nott.ac.uk/~psxip1/#FRPRefactored>).
 --
---   - "Data.MonadicStreamFunction.Instances.ArrowChoice"
---   - "Data.MonadicStreamFunction.Instances.ArrowLoop"
---   - "Data.MonadicStreamFunction.Instances.ArrowPlus"
-
+-- Apart from the modules exported, this module exports instances from:
+--
+-- - "Data.MonadicStreamFunction.Instances.ArrowChoice"
+-- - "Data.MonadicStreamFunction.Instances.ArrowLoop"
+-- - "Data.MonadicStreamFunction.Instances.ArrowPlus"
 module Data.MonadicStreamFunction
   ( module Control.Arrow
   , module Data.MonadicStreamFunction.Core
@@ -43,17 +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
@@ -1,59 +1,61 @@
--- | This module contains operations on monadic streams that are asynchronous,
---   i.e. that change the speed at which data enters or leaves the 'MSF'.
-
+-- |
+-- Copyright  : (c) Ivan Perez and Manuel Baerenz, 2016
+-- License    : BSD3
+-- Maintainer : ivan.perez@keera.co.uk
+--
+-- This module contains operations on monadic streams that are asynchronous,
+-- 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
-import Data.MonadicStreamFunction.Util (MStream)
-
-{- |
-Concatenates a monadic stream of lists to a monadic stream.
-The stream of lists will be called exactly when new data is needed.
-
-Example:
-
->>> 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
-Enter a list of Ints:
-[]
-Enter a list of Ints:
-[]
-Enter a list of Ints:
-[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:
-
->>> let boolToList b = if b then ["Yes"] else []
->>> let everyOddEmpty = count >>> arr (even >>> boolToList)
->>> reactimate $ concatS everyOddEmpty >>> arrM print
-"Yes"
-"Yes"
-"Yes"
-"Yes"
-"Yes"
-...
-
-But this will be caught in a loop:
+-- Internal imports
+import Data.MonadicStreamFunction.InternalCore (MSF(MSF, unMSF))
+import Data.MonadicStreamFunction.Util         (MStream)
 
->>> let after3Empty = count >>> arr ((<= 3) >>> boolToList)
->>> reactimate $ concatS after3Empty  >>> arrM print
-"Yes"
-"Yes"
-"Yes"
-^CInterrupted.
--}
+-- |
+-- Concatenates a monadic stream of lists to a monadic stream.
+-- The stream of lists will be called exactly when new data is needed.
+--
+-- Example:
+--
+-- >>> 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
+-- Enter a list of Ints:
+-- []
+-- Enter a list of Ints:
+-- []
+-- Enter a list of Ints:
+-- [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:
+--
+-- >>> let boolToList b = if b then ["Yes"] else []
+-- >>> let everyOddEmpty = count >>> arr (even >>> boolToList)
+-- >>> reactimate $ concatS everyOddEmpty >>> arrM print
+-- "Yes"
+-- "Yes"
+-- "Yes"
+-- "Yes"
+-- "Yes"
+-- ...
+--
+-- But this will be caught in a loop:
+--
+-- >>> let after3Empty = count >>> arr ((<= 3) >>> boolToList)
+-- >>> reactimate $ concatS after3Empty  >>> arrM print
+-- "Yes"
+-- "Yes"
+-- "Yes"
+-- ^CInterrupted.
 concatS :: Monad m => MStream m [b] -> MStream m b
 concatS msf = MSF $ \_ -> tick msf []
   where
@@ -61,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,33 +1,44 @@
+{-# LANGUAGE CPP        #-}
 {-# LANGUAGE Rank2Types #-}
--- | Monadic Stream Functions are synchronized stream functions
---   with side effects.
+-- 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
+-- Maintainer : ivan.perez@keera.co.uk
 --
---   'MSF's are defined by a function
---   @unMSF :: MSF m a b -> a -> m (b, MSF m a b)@
---   that executes one step of a simulation, and produces an output in a
---   monadic context, and a continuation to be used for future steps.
+-- Monadic Stream Functions are synchronized stream functions with side
+-- effects.
 --
---   'MSF's are a generalisation of the implementation mechanism used by Yampa,
---   Wormholes and other FRP and reactive implementations.
+-- 'MSF's are defined by a function
+-- @unMSF :: MSF m a b -> a -> m (b, MSF m a b)@
+-- that executes one step of a simulation, and produces an output in a monadic
+-- context, and a continuation to be used for future steps.
 --
---   When combined with different monads, they produce interesting effects. For
---   example, when combined with the 'Maybe' monad, they become transformations
---   that may stop producing outputs (and continuations). The 'Either' monad
---   gives rise to 'MSF's that end with a result (akin to Tasks in Yampa, and
---   Monadic FRP).
+-- 'MSF's are a generalisation of the implementation mechanism used by Yampa,
+-- Wormholes and other FRP and reactive implementations.
 --
---   Flattening, that is, going from some structure @MSF (t m) a b@ to @MSF m a b@
---   for a specific transformer @t@ often gives rise to known FRP constructs.
---   For instance, flattening with 'EitherT' gives rise to switching, and
---   flattening with 'ListT' gives rise to parallelism with broadcasting.
+-- When combined with different monads, they produce interesting effects. For
+-- example, when combined with the 'Maybe' monad, they become transformations
+-- that may stop producing outputs (and continuations). The 'Either' monad
+-- gives rise to 'MSF's that end with a result (akin to Tasks in Yampa, and
+-- Monadic FRP).
 --
---   'MSF's can be used to implement many FRP variants, including Arrowized FRP,
---   Classic FRP, and plain reactive programming. Arrowized and applicative
---   syntax are both supported.
+-- Flattening, that is, going from some structure @MSF (t m) a b@ to @MSF m a b@
+-- for a specific transformer @t@ often gives rise to known FRP constructs.
+-- For instance, flattening with 'EitherT' gives rise to switching, and
+-- flattening with 'ListT' gives rise to parallelism with broadcasting.
 --
---   For a very detailed introduction to 'MSF's, see:
---   <http://dl.acm.org/citation.cfm?id=2976010>
---   (mirror: <http://www.cs.nott.ac.uk/~psxip1/#FRPRefactored>).
+-- 'MSF's can be used to implement many FRP variants, including Arrowized FRP,
+-- Classic FRP, and plain reactive programming. Arrowized and applicative
+-- syntax are both supported.
+--
+-- For a very detailed introduction to 'MSF's, see:
+-- <http://dl.acm.org/citation.cfm?id=2976010>
+-- (mirror: <http://www.cs.nott.ac.uk/~psxip1/#FRPRefactored>).
 module Data.MonadicStreamFunction.Core
   ( -- * Types
     MSF
@@ -51,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, morphGS, feedback, reactimate, embed)
+#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
 
@@ -107,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
@@ -125,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
@@ -138,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
@@ -151,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:
@@ -163,27 +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
-
--- IPerez: There is an alternative signature for liftMStreamPurer that also
--- works, and makes the code simpler:
---
--- morphS :: Monad m => (m1 (b, MSF m1 a b) -> m (b, MSF m1 a b)) -> MSF m1 a b -> MSF m a b
---
--- Then we can express:
---
--- liftTransS = morphS lift
--- liftBaseS  = morphS liftBase
---
--- We could also define a strict version of morphS as follows:
---
--- morphS'  f = morphS (f >=> whnfVal)
---   where whnfVal p@(b,_) = b `seq` return p
---
--- and leave morphS as a lazy version (by default).
+    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
@@ -1,14 +1,21 @@
-{-# LANGUAGE InstanceSigs         #-}
+{-# LANGUAGE InstanceSigs #-}
 {-# OPTIONS_GHC -fno-warn-orphans #-}
--- | Instance of 'ArrowChoice' for Monadic Stream Functions ('MSF').
+-- |
+-- Copyright  : (c) Ivan Perez and Manuel Baerenz, 2016
+-- License    : BSD3
+-- Maintainer : ivan.perez@keera.co.uk
 --
---   Import this module to include that (orphan) instance.
+-- Instance of 'ArrowChoice' for Monadic Stream Functions ('MSF').
+--
+-- 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
@@ -1,24 +1,30 @@
-{-# LANGUAGE InstanceSigs         #-}
-{-# LANGUAGE RecursiveDo          #-}
+{-# LANGUAGE InstanceSigs #-}
+{-# LANGUAGE RecursiveDo  #-}
 {-# OPTIONS_GHC -fno-warn-orphans #-}
--- | Instance of 'ArrowLoop' for Monadic Stream Functions ('MSF').
+-- |
+-- Copyright  : (c) Ivan Perez and Manuel Baerenz, 2016
+-- License    : BSD3
+-- Maintainer : ivan.perez@keera.co.uk
 --
---   Import this module to include that (orphan) instance.
+-- Instance of 'ArrowLoop' for Monadic Stream Functions ('MSF').
 --
---   This is only defined for monads that are instances of 'MonadFix'.
+-- Import this module to include that (orphan) instance.
+--
+-- This is only defined for monads that are instances of 'MonadFix'.
 module Data.MonadicStreamFunction.Instances.ArrowLoop where
 
-import Data.MonadicStreamFunction.Core
-import Data.MonadicStreamFunction.InternalCore
+-- External imports
+import Control.Arrow     (ArrowLoop (..))
+import Control.Monad.Fix (MonadFix)
 
--- External
-import Control.Arrow
-import Control.Monad.Fix
+-- 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
@@ -1,30 +1,37 @@
 {-# OPTIONS_GHC -fno-warn-orphans #-}
--- | Instance of 'ArrowPlus' for Monadic Stream Functions ('MSF').
+-- |
+-- Copyright  : (c) Ivan Perez and Manuel Baerenz, 2016
+-- License    : BSD3
+-- Maintainer : ivan.perez@keera.co.uk
 --
---   Import this module to include that (orphan) instance.
+-- Instance of 'ArrowPlus' for Monadic Stream Functions ('MSF').
 --
---   This is only defined for monads that are instances of 'MonadPlus'.
+-- Import this module to include that (orphan) instance.
+--
+-- This is only defined for monads that are instances of 'MonadPlus'.
 module Data.MonadicStreamFunction.Instances.ArrowPlus where
 
--- base
-import Control.Arrow
-import Control.Monad
-import Control.Applicative
+-- 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,10 +1,13 @@
-{-# LANGUAGE TypeFamilies         #-}
 {-# OPTIONS_GHC -fno-warn-orphans #-}
-
--- | Number instances for 'MSF's that produce numbers. This allows you to use
---   numeric operators with 'MSF's that output numbers, for example,
---   you can write:
+-- |
+-- Copyright  : (c) Ivan Perez and Manuel Baerenz, 2016
+-- License    : BSD3
+-- Maintainer : ivan.perez@keera.co.uk
 --
+-- Number instances for 'MSF's that produce numbers. This allows you to use
+-- numeric operators with 'MSF's that output numbers, for example, you can
+-- write:
+--
 -- @
 -- msf1 :: MSF Input Double -- defined however you want
 -- msf2 :: MSF Input Double -- defined however you want
@@ -18,13 +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,12 +1,17 @@
+{-# LANGUAGE FlexibleContexts      #-}
 {-# LANGUAGE FlexibleInstances     #-}
 {-# LANGUAGE MultiParamTypeClasses #-}
-{-# LANGUAGE TypeFamilies          #-}
 {-# LANGUAGE UndecidableInstances  #-}
-{-# OPTIONS_GHC -fno-warn-orphans  #-}
--- | '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:
+{-# OPTIONS_GHC -fno-warn-orphans #-}
+-- |
+-- Copyright  : (c) Ivan Perez and Manuel Baerenz, 2016
+-- License    : BSD3
+-- 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:
+--
 -- @
 -- msf1 :: MSF Input (Double, Double) -- defined however you want
 -- msf2 :: MSF Input (Double, Double) -- defined however you want
@@ -21,7 +26,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
@@ -30,16 +35,27 @@
 -- resolved.
 module Data.MonadicStreamFunction.Instances.VectorSpace where
 
-import Control.Arrow
-import Control.Arrow.Util
-import Data.MonadicStreamFunction.Core
-import Data.VectorSpace
+-- External imports
+import Control.Arrow    ((>>^))
+import Data.VectorSpace (VectorSpace (..))
 
+-- 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
-  zeroVector   = constantly zeroVector
-  r   *^ msf   = msf >>^ (r *^)
-  msf ^/ r     = msf >>^ (^/ r)
-  (^+^)        = elementwise2 (^+^)
-  (^-^)        = elementwise2 (^-^)
-  negateVector = (>>^ negateVector)
+instance (Monad m, Eq s, Num s, VectorSpace v s, Floating (MSF m a s))
+      => VectorSpace (MSF m a v) (MSF m a s)
+  where
+    zeroVector   = constantly zeroVector
+    (*^)         = elementwise2 (*^)
+    (^/)         = elementwise2 (^/)
+    (^+^)        = elementwise2 (^+^)
+    (^-^)        = elementwise2 (^-^)
+    negateVector = (>>^ negateVector)
+    dot          = elementwise2 dot
+    normalize v  = elementwise2 f v (norm v)
+      where
+        f v' nv'
+          | nv' /= 0  = v' ^/ nv'
+          | otherwise = error "normalize: zero vector"
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,52 +1,52 @@
-{-# LANGUAGE ExplicitForAll #-}
-{-# LANGUAGE Rank2Types     #-}
--- | Monadic Stream Functions are synchronized stream functions
---   with side effects.
+{-# LANGUAGE Rank2Types #-}
+-- |
+-- Copyright  : (c) Ivan Perez and Manuel Baerenz, 2016
+-- License    : BSD3
+-- Maintainer : ivan.perez@keera.co.uk
 --
---   'MSF's are defined by a function
---   @unMSF :: MSF m a b -> a -> m (b, MSF m a b)@
---   that executes one step of a simulation, and produces an output in a
---   monadic context, and a continuation to be used for future steps.
+-- Monadic Stream Functions are synchronized stream functions with side
+-- effects.
 --
---   'MSF's are a generalisation of the implementation mechanism used by Yampa,
---   Wormholes and other FRP and reactive implementations.
+-- 'MSF's are defined by a function
+-- @unMSF :: MSF m a b -> a -> m (b, MSF m a b)@
+-- that executes one step of a simulation, and produces an output in a monadic
+-- context, and a continuation to be used for future steps.
 --
---   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.
-
+-- '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. By default, you should import
+-- "Data.MonadicStreamFunction.Core" or "Data.MonadicStreamFunction" whenever
+-- possible, and define your functions without accessing the MSF constructor.
+-- 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.Arrow
-import Control.Applicative
-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
 
@@ -62,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
@@ -77,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@
@@ -110,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
@@ -1,18 +1,22 @@
--- | Versions of arrow combinators that run things in parallel using 'par', if
+-- |
+-- Copyright  : (c) Ivan Perez and Manuel Baerenz, 2016
+-- License    : BSD3
+-- Maintainer : ivan.perez@keera.co.uk
+--
+-- Versions of arrow combinators that run things in parallel using 'par', if
 -- 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
@@ -1,31 +1,31 @@
--- | 'ReactHandle's.
+-- |
+-- Copyright  : (c) Ivan Perez and Manuel Baerenz, 2016
+-- License    : BSD3
+-- Maintainer : ivan.perez@keera.co.uk
 --
--- 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.
-
+-- '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.
 module Data.MonadicStreamFunction.ReactHandle where
 
--- External
-import Control.Monad.IO.Class
-import Data.IORef
-
--- Internal
-import Data.MonadicStreamFunction
-import Data.MonadicStreamFunction.InternalCore
+-- External imports
+import Control.Monad.IO.Class (MonadIO, liftIO)
+import Data.IORef             (IORef, newIORef, readIORef, writeIORef)
 
+-- 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,40 +1,40 @@
-{-# LANGUAGE Arrows     #-}
-{-# LANGUAGE Rank2Types #-}
--- | Useful auxiliary functions and definitions.
+{-# LANGUAGE Arrows #-}
+{-# LANGUAGE CPP    #-}
+-- |
+-- Copyright  : (c) Ivan Perez and Manuel Baerenz, 2016
+-- License    : BSD3
+-- Maintainer : ivan.perez@keera.co.uk
+--
+-- 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
+-- 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 Data.MonadicStreamFunction.Core
-import Data.MonadicStreamFunction.Instances.ArrowChoice ()
-import Data.VectorSpace
-import Prelude hiding (id, (.))
+#if !MIN_VERSION_base(4,8,0)
+import Data.Monoid (Monoid, mempty, mappend)
+#endif
 
-import Control.Monad.Trans.MSF.State
+-- 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)
@@ -55,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.
@@ -78,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
@@ -116,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
 
@@ -137,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.
@@ -159,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
 
