diff --git a/ChangeLog.md b/ChangeLog.md
deleted file mode 100644
--- a/ChangeLog.md
+++ /dev/null
@@ -1,31 +0,0 @@
-# Revision history for rhine
-
-The version numbering follows the package `dunai`.
-Since `rhine` reexports modules from `dunai`,
-every major version in `dunai` triggers a major version in `rhine`.
-
-## 0.4.0.0 -- 2017.12.04
-
-* Documentation typos fixed
-* Added `ChangeLog.md`
-
-## 0.3.0.0
-
-* Version bump
-* Documentation typos fixed (Thanks to Gabor Greif)
-
-## 0.2.0.0
-
-* Travis CI support
-* Removed several utilities that are now in `dunai`
-* Extended averaging functions
-
-## 0.1.1.0
-
-* Added `FRP.Rhine.Clock.Realtime.Stdin` (console keyboard event clock)
-* Added `FRP.Rhine.Clock.Select` (event selection clock)
-* Added `FRP.Rhine.SyncSF.Except` (synchronous exception handling)
-
-## 0.1.0.0
-
-* Initial version
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-# README
+* README
 --------
 
 This is the main library.
diff --git a/rhine.cabal b/rhine.cabal
--- a/rhine.cabal
+++ b/rhine.cabal
@@ -1,6 +1,6 @@
 name:                rhine
 
-version:             0.4.0.0
+version:             0.4.0.1
 
 synopsis: Functional Reactive Programming with type-level clocks
 
@@ -33,8 +33,6 @@
 
 build-type:          Simple
 
-extra-source-files:  ChangeLog.md
-
 extra-doc-files:     README.md
 
 cabal-version:       >=1.18
@@ -46,7 +44,7 @@
 source-repository this
   type:     git
   location: git@github.com:turion/rhine.git
-  tag:      v0.4.0.0
+  tag:      v0.4.0.1
 
 
 library
@@ -81,15 +79,18 @@
     FRP.Rhine.SyncSF.Except
     FRP.Rhine.TimeDomain
 
+  other-modules:
+    FRP.Rhine.SyncSF.Except.Util
+
   -- LANGUAGE extensions used by modules in this package.
   -- other-extensions:
 
   -- Other library packages from which modules are imported.
-  build-depends:       base         >= 4.7   && < 5
+  build-depends:       base         >= 4.9
                     ,  dunai        == 0.4.0.*
                     ,  transformers >= 0.4   && < 0.6
-                    ,  time         >= 1.6   && < 1.7
-                    ,  free         >= 4.12  && < 4.13
+                    ,  time         == 1.8.*
+                    ,  free         == 5.0.*
                     ,  containers   >= 0.5   && < 0.6
 
   -- Directories containing source files.
diff --git a/src/FRP/Rhine/Clock/Realtime/Stdin.hs b/src/FRP/Rhine/Clock/Realtime/Stdin.hs
--- a/src/FRP/Rhine/Clock/Realtime/Stdin.hs
+++ b/src/FRP/Rhine/Clock/Realtime/Stdin.hs
@@ -5,6 +5,7 @@
 
 -- base
 import Data.Time.Clock
+import Data.Semigroup
 
 -- transformers
 import Control.Monad.IO.Class
@@ -29,6 +30,9 @@
         &&& arrM_ (liftIO getLine)
       , initialTime
       )
+
+instance Semigroup StdinClock where
+  _ <> _ = StdinClock
 
 instance Monoid StdinClock where
   mempty      = StdinClock
diff --git a/src/FRP/Rhine/SyncSF/Except.hs b/src/FRP/Rhine/SyncSF/Except.hs
--- a/src/FRP/Rhine/SyncSF/Except.hs
+++ b/src/FRP/Rhine/SyncSF/Except.hs
@@ -22,10 +22,28 @@
 
 -- rhine
 import FRP.Rhine
+import FRP.Rhine.SyncSF.Except.Util
 
+-- * Types
 
+{- | A synchronous exception-throwing signal function.
+It is based on a @newtype@, 'MSFExcept',
+to exhibit a monad interface /in the exception type/.
+`return` then corresponds to throwing an exception,
+and `(>>=)` is exception handling.
+(For more information, see the documentation of 'MSFExcept'.)
+
+* @m@:  The monad that the signal function may take side effects in
+* @cl@: The clock on which the signal function ticks
+* @a@:  The input type
+* @b@:  The output type
+* @e@:  The type of exceptions that can be thrown
+-}
 type SyncExcept m cl a b e = MSFExcept (ReaderT (TimeInfo cl) m) a b e
 
+{- | A clock polymorphic 'SyncExcept'.
+Any clock with time domain @td@ may occur.
+-}
 type BehaviourFExcept m td a b e
   = forall cl. td ~ TimeDomainOf cl => SyncExcept m cl a b e
 
@@ -33,12 +51,16 @@
 type BehaviorFExcept m td a b e = BehaviourFExcept m td a b e
 
 
--- | Commute the effects of the |ReaderT| and the |ExceptT| monad.
-commuteReaderExcept :: ReaderT r (ExceptT e m) a -> ExceptT e (ReaderT r m) a
-commuteReaderExcept a = ExceptT $ ReaderT $ \r -> runExceptT $ runReaderT a r
 
+commuteExceptReader :: ExceptT e (ReaderT r m) a -> ReaderT r (ExceptT e m) a
+commuteExceptReader a = ReaderT $ \r -> ExceptT $ runReaderT (runExceptT a) r
+
+runSyncExcept :: Monad m => SyncExcept m cl a b e -> SyncSF (ExceptT e m) cl a b
+runSyncExcept = liftMSFPurer commuteExceptReader . runMSFExcept
+
 -- | Enter the monad context in the exception
 --   for |SyncSF|s in the |ExceptT| monad.
+--   The 'SyncSF' will be run until it encounters an exception.
 try :: Monad m => SyncSF (ExceptT e m) cl a b -> SyncExcept m cl a b e
 try = MSFE.try . liftMSFPurer commuteReaderExcept
 
@@ -51,17 +73,19 @@
 once_ :: Monad m => m e -> SyncExcept m cl a b e
 once_ = once . const
 
--- |
+-- | Immediately throw the exception on the input.
 throwS :: Monad m => SyncSF (ExceptT e m) cl e a
 throwS = arrMSync throwE
 
+-- | Throw the given exception when the 'Bool' turns true.
+throwOn :: Monad m => e -> SyncSF (ExceptT e m) cl Bool ()
+throwOn e = proc b -> throwOn' -< (b, e)
+
+-- | Variant of 'throwOn', where the exception can vary every tick.
 throwOn' :: Monad m => SyncSF (ExceptT e m) cl (Bool, e) ()
 throwOn' = proc (b, e) -> if b
   then throwS  -< e
   else returnA -< ()
-
-throwOn :: Monad m => e -> SyncSF (ExceptT e m) cl Bool ()
-throwOn e = proc b -> throwOn' -< (b, e)
 
 
 -- | Advances a single tick with the given Kleisli arrow,
diff --git a/src/FRP/Rhine/SyncSF/Except/Util.hs b/src/FRP/Rhine/SyncSF/Except/Util.hs
new file mode 100644
--- /dev/null
+++ b/src/FRP/Rhine/SyncSF/Except/Util.hs
@@ -0,0 +1,12 @@
+{-| Utilities for 'FRP.Rhine.SyncSF.Except' that need not be exported.
+-}
+module FRP.Rhine.SyncSF.Except.Util where
+
+-- transformers
+import Control.Monad.Trans.Except
+import Control.Monad.Trans.Reader
+
+
+-- | Commute the effects of the |ReaderT| and the |ExceptT| monad.
+commuteReaderExcept :: ReaderT r (ExceptT e m) a -> ExceptT e (ReaderT r m) a
+commuteReaderExcept a = ExceptT $ ReaderT $ \r -> runExceptT $ runReaderT a r
