diff --git a/Changelog b/Changelog
--- a/Changelog
+++ b/Changelog
@@ -1,5 +1,12 @@
+0.3.3   (2020-10-06)
+	* use only one `MVar` per `IVar` instead of two, taking advantage
+	  of the fact that `readMVar` has been atomic since ghc 7.10
+	* add `Eq` instance and `uncons` operation for `IChan`
+	  (suggested by ski@Freenode)
+
 0.3.2   (2015-10-29)
-	* add Eq instances for `IVar` and `MIChan`
+	* add `Eq` instances for `IVar` and `MIChan`
+	  (suggested by nwf@Freenode)
 
 0.3.1   (2015-07-02)
 	* fix building with ghc 7.8
diff --git a/LICENSE b/LICENSE
--- a/LICENSE
+++ b/LICENSE
@@ -1,4 +1,4 @@
-Copyright (c) 2008-2015 Bertram Felgenhauer
+Copyright (c) 2008-2020 Bertram Felgenhauer
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
diff --git a/Sample.hs b/Sample.hs
new file mode 100644
--- /dev/null
+++ b/Sample.hs
@@ -0,0 +1,23 @@
+import qualified Data.IVar.Simple as IVar
+import Control.Concurrent
+
+main :: IO ()
+main = do
+    -- create new `IVar`
+    iv <- IVar.new
+    -- spawn a thread that reads the `IVar` and prints the value
+    forkIO $ print (IVar.read iv)
+    -- the spawned thread will sleep while the `IVar` is empty
+    threadDelay 1000000
+    -- tentatively read the `IVar` -- it's still empty
+    IVar.tryRead iv >>= print
+    -- write a value to the `IVar`
+    IVar.write iv 42
+    -- now the thread will be woken up and print "42"
+    threadDelay 1000000
+    -- tentatively read the `IVar` -- now it's full
+    IVar.tryRead iv >>= print
+    -- further writes fail: `tryWrite` returns `False`
+    IVar.tryWrite iv 42 >>= print
+    -- and `write` throws an exception
+    IVar.write iv 42
diff --git a/ivar-simple.cabal b/ivar-simple.cabal
--- a/ivar-simple.cabal
+++ b/ivar-simple.cabal
@@ -1,8 +1,8 @@
 name:          ivar-simple
-version:       0.3.2
+version:       0.3.3
 category:      Concurrency
 stability:     experimental
-copyright:     (c) 2008-2015 Bertram Felgenhauer
+copyright:     (c) 2008-2020 Bertram Felgenhauer
 maintainer:    Bertram Felgenhauer <int-e@gmx.de>
 license:       MIT
 license-file:  LICENSE
@@ -12,11 +12,12 @@
   .
   They can be read, an operation that will block until a value was written
   to the variable. They can be written to exactly once.
-cabal-version: >= 1.6
+cabal-version: >= 1.10
 build-type:    Simple
 extra-source-files:
     README.md
     Changelog
+    Sample.hs
 
 source-repository head
   type:                 git
@@ -30,7 +31,9 @@
         Data.IVar.Simple
         Data.IVar.Simple.IChan
         Data.IVar.Simple.MIChan
+    default-language:
+        Haskell2010
     build-depends:
-        base >= 4 && < 5
-    extensions:
+        base >= 4.7 && < 5
+    other-extensions:
         DeriveDataTypeable
diff --git a/src/Data/IVar/Simple.hs b/src/Data/IVar/Simple.hs
--- a/src/Data/IVar/Simple.hs
+++ b/src/Data/IVar/Simple.hs
@@ -1,8 +1,8 @@
-{-# LANGUAGE DeriveDataTypeable, CPP #-}
+{-# LANGUAGE DeriveDataTypeable #-}
 -- |
 -- Module      : Data.IVar.Simple
--- Copyright   : (c) 2008-2015 Bertram Felgenhauer
--- License     : BSD3
+-- Copyright   : (c) 2008-2020 Bertram Felgenhauer
+-- License     : MIT
 --
 -- Maintainer  : Bertram Felgenhauer <int-e@gmx.de>
 -- Stability   : experimental
@@ -35,42 +35,41 @@
 import Prelude hiding (read)
 
 -- | A write-once (/immutable/) Variable
-data IVar a = IVar (MVar ()) (MVar a) a
+data IVar a = IVar (MVar a) a
 
 instance Eq (IVar a) where
-    IVar lock1 _ _ == IVar lock2 _ _ = lock1 == lock2
+    IVar trans1 _ == IVar trans2 _ = trans1 == trans2
     -- note: it would be possible to generalize the type to
     -- eqIVar :: IVar a -> IVar b -> Bool  (but would that be useful?)
 
 -- | Create a new, empty 'IVar'.
 new :: IO (IVar a)
 new = do
-    lock <- newMVar ()
     trans <- newEmptyMVar
     let {-# NOINLINE value #-}
-        value = unsafePerformIO $ takeMVar trans
-    return (IVar lock trans value)
+        value = unsafePerformIO $ readMVar trans
+    return (IVar trans value)
 
 -- | Create a new filled 'IVar'.
 --
 -- This is slightly cheaper than creating a new 'IVar' and then writing to it.
 newFull :: a -> IO (IVar a)
 newFull value = do
-    lock <- newEmptyMVar
-    return (IVar lock (error "unused MVar") value)
+    trans <- newMVar (error "unused value")
+    return (IVar trans value)
 
 -- | Returns the value of an 'IVar'.
 --
 -- The evaluation will block until a value is written to the 'IVar' if it
 -- has no value yet.
 read :: IVar a -> a
-read (IVar _ _ value) = value
+read (IVar _ value) = value
 
 -- | Try to read an 'IVar'. Returns 'Nothing' if it has no value yet.
 tryRead :: IVar a -> IO (Maybe a)
-tryRead (IVar lock _ value) = do
-    empty <- isEmptyMVar lock
-    if empty then return (Just value) else return Nothing
+tryRead (IVar trans value) = do
+    empty <- isEmptyMVar trans
+    if not empty then return (Just value) else return Nothing
 
 -- | Writes a value to an 'IVar'. Raises a 'BlockedIndefinitelyOnIVar'
 -- exception if the variable already has a value.
@@ -84,15 +83,7 @@
 -- | Writes a value to an 'IVar'. Returns 'True' if successful, and
 -- 'False' otherwise.
 tryWrite :: IVar a -> a -> IO Bool
-tryWrite (IVar lock trans _) value = block $ do
-    a <- tryTakeMVar lock
-    case a of
-        Just _  -> putMVar trans value >> return True
-        Nothing -> return False
-#if __GLASGOW_HASKELL__ >= 708
-  where
-    block = mask_
-#endif
+tryWrite (IVar trans _) value = tryPutMVar trans value
 
 -- | The thread has attempted to write to a full 'IVar'.
 data BlockedIndefinitelyOnIVar = BlockedIndefinitelyOnIVar
diff --git a/src/Data/IVar/Simple/IChan.hs b/src/Data/IVar/Simple/IChan.hs
--- a/src/Data/IVar/Simple/IChan.hs
+++ b/src/Data/IVar/Simple/IChan.hs
@@ -1,7 +1,7 @@
 -- |
 -- Module      : Data.IVar.Simple.IChan
--- Copyright   : (c) 2008-2012 Bertram Felgenhauer
--- License     : BSD3
+-- Copyright   : (c) 2008-2020 Bertram Felgenhauer
+-- License     : MIT
 --
 -- Maintainer  : Bertram Felgenhauer <int-e@gmx.de>
 -- Stability   : experimental
@@ -19,6 +19,7 @@
     IChan,
     new,
     read,
+    uncons,
     write,
     tryWrite,
 ) where
@@ -30,6 +31,7 @@
 
 -- | A channel head
 newtype IChan a = IChan (IVar.IVar (a, IChan a))
+    deriving Eq
 
 -- | Create a new channel.
 new :: IO (IChan a)
@@ -41,7 +43,15 @@
 -- This is a pure computation. Forcing elements of the list may, however,
 -- block.
 read :: IChan a -> [a]
-read (IChan as) = let (a, ic) = IVar.read as in a : read ic
+read ic = let (a, ic') = uncons ic in a : read ic'
+
+-- | Split channel into head and tail.
+--
+-- This is a pure operation, but it may block.
+--
+-- @since 0.3.3
+uncons :: IChan a -> (a, IChan a)
+uncons (IChan as) = IVar.read as
 
 -- | Write a single value to the channel.
 --
diff --git a/src/Data/IVar/Simple/MIChan.hs b/src/Data/IVar/Simple/MIChan.hs
--- a/src/Data/IVar/Simple/MIChan.hs
+++ b/src/Data/IVar/Simple/MIChan.hs
@@ -1,7 +1,7 @@
 -- |
 -- Module      : Data.IVar.Simple.MIChan
--- Copyright   : (c) 2008-2012 Bertram Felgenhauer
--- License     : BSD3
+-- Copyright   : (c) 2008-2015 Bertram Felgenhauer
+-- License     : MIT
 --
 -- Maintainer  : Bertram Felgenhauer <int-e@gmx.de>
 -- Stability   : experimental
