diff --git a/src/Data/Unamb.hs b/src/Data/Unamb.hs
--- a/src/Data/Unamb.hs
+++ b/src/Data/Unamb.hs
@@ -1,4 +1,4 @@
-{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE ScopedTypeVariables, RecursiveDo, CPP #-}
 {-# OPTIONS_GHC -Wall #-}
 ----------------------------------------------------------------------
 -- |
@@ -12,18 +12,24 @@
 -- Unambiguous choice
 ----------------------------------------------------------------------
 
+#include "Typeable.h"
+
 module Data.Unamb
   (
-    unamb, amb, race, assuming, hang, asAgree
+    bottom, unamb, assuming, asAgree, hang
+  , amb, race
   ) where
 
+import Prelude hiding (catch)
 -- For hang
-import Control.Monad (forever)
+-- import Control.Monad (forever)
 import System.IO.Unsafe
 
--- For unamb
+-- import Data.Dynamic
+
 import Control.Concurrent
-import Control.Exception (evaluate)
+import Control.Exception
+  (evaluate, BlockedOnDeadMVar(..), catch, throw)
 
 
 -- | Unambiguous choice operator.  Equivalent to the ambiguous choice
@@ -43,35 +49,50 @@
 -- whichever finishes first.  See also 'amb'.  Thanks to Spencer Janssen
 -- for this simple version.
 race :: IO a -> IO a -> IO a
+
 a `race` b = do v  <- newEmptyMVar
-                ta <- forkIO (a >>= putMVar v)
-                tb <- forkIO (b >>= putMVar v)
+                ta <- forkIO' (a >>= putMVar v)
+                tb <- forkIO' (b >>= putMVar v)
                 x  <- takeMVar v
                 killThread ta
                 killThread tb
                 return x
 
--- Without using unsafePerformIO, is there a way to define a
--- non-terminating but non-erroring pure value that consume very little
--- resources while not terminating?
+-- Use a particular exception as our representation for waiting forever.
+-- A thread can bottom-out efficiently by throwing that exception.  If both
+-- threads bail out, then the 'takeMVar' would block.  In that case, the
+-- run-time system would notice and raise 'BlockedOnDeadMVar'.  I'd then
+-- want to convert that exception into the one that wait-forever
+-- exception.  As an expedient hack, I use 'BlockedOnDeadMVar' as the
+-- wait-forever exception, so that no conversion is needed.  Perhaps
+-- revisit this choice, and define our own exception class, for clarity
+-- and easier debugging.
 
+
+-- Fork a thread to execute a given action.  Silence any raised exceptions.
+forkIO' :: IO () -> IO ThreadId
+forkIO' act = forkIO (act `catch` handler)
+ where
+   handler :: BlockedOnDeadMVar -> IO ()
+   handler = const (return ())
+
+-- I'd like @hang `unamb` hang@ to quickly terminate, throwing an
+-- exception.  I'm surprised that it doesn't lead to 'BlockedOnDeadMVar'.
+-- Why doesn't it??  Oh -- maybe it does, when compiled.
+
+
+-- | A 'bottom' value, allowing no information out.  A left- and right-
+-- identity for 'unamb'.  At the top level, evaluating 'bottom' results in
+-- the message "Exception: thread blocked indefinitely".
+bottom :: a
+bottom = throw BlockedOnDeadMVar
+
+-- {-# DEPRECATED hang "use bottom instead" #-}
+
 -- | Never yield an answer.  Like 'undefined' or 'error "whatever"', but
 -- don't raise an error, and don't consume computational resources.
 hang :: a
-hang = unsafePerformIO hangIO
-
--- | Block forever.
-hangIO :: IO a
-hangIO = do -- putStrLn "warning: blocking forever."
-            -- Any never-terminating computation goes here
-            -- This one can yield an exception "thread blocked indefinitely"
-            -- newEmptyMVar >>= takeMVar
-            -- sjanssen suggests this alternative:
-            forever $ threadDelay maxBound
-            -- forever's return type is (), though it could be fully
-            -- polymorphic.  Until it's fixed, I need the following line.
-            return undefined
-
+hang = bottom
 
 -- | Yield a value if a condition is true.  Otherwise wait forever.
 assuming :: Bool -> a -> a
@@ -80,3 +101,19 @@
 -- | The value of agreeing values (or hang)
 asAgree :: Eq a => a -> a -> a
 a `asAgree` b = assuming (a == b) a
+
+----
+
+{-
+
+data WaitForever = WaitForever
+
+INSTANCE_TYPEABLE0(WaitForever,waitForeverTc,"WaitForever")
+
+instance Show WaitForever where
+    showsPrec _ WaitForever = showString "waiting for, like, evar"
+instance Exception WaitForever
+
+-}
+
+----
diff --git a/unamb.cabal b/unamb.cabal
--- a/unamb.cabal
+++ b/unamb.cabal
@@ -1,5 +1,5 @@
 Name:                unamb
-Version:             0.0.1
+Version:             0.1.0
 Cabal-Version:       >= 1.2
 Synopsis:            Unambiguous choice
 Category:            Concurrency, Data, Other
@@ -10,9 +10,6 @@
   package in order to encourage experimentation.
   .
   Project wiki page: <http://haskell.org/haskellwiki/unamb>
-  .
-  The module documentation pages have links to colorized source code and
-  to wiki pages where you can read and contribute user comments.  Enjoy!
   .
   &#169; 2008 by Conal Elliott; BSD3 license.
   .
diff --git a/wikipage.tw b/wikipage.tw
--- a/wikipage.tw
+++ b/wikipage.tw
@@ -7,9 +7,9 @@
 <hask>unamb</hask> was originally a part of [[Reactive]].  I moved it to its own package in order to encourage experimentation.
 
 Besides this wiki page, here are more ways to find out about unamb:
-* Read [http://code.haskell.org/unamb/doc/html/ the library documentation].
-* Get the code repository: '''<tt>darcs get http://code.haskell.org/unamb</tt>'''.
-* Install from [http://hackage.haskell.org/cgi-bin/hackage-scripts/package/unamb Hackage].
-* See the [[unamb/Versions| version history]].
+* Visit the [http://hackage.haskell.org/cgi-bin/hackage-scripts/package/unamb Hackage page] for library documentation and to download & install.
+* Or install with <tt>cabal install unamb</tt>.
+* Get the code repository: <tt>darcs get http://code.haskell.org/unamb</tt>.
+<!-- * See the [[unamb/Versions| version history]]. -->
 
 Please leave comments at the [[Talk:unamb|Talk page]].
