diff --git a/Data/BloomFilter.hs b/Data/BloomFilter.hs
--- a/Data/BloomFilter.hs
+++ b/Data/BloomFilter.hs
@@ -49,6 +49,7 @@
     -- ** Accessors
     , lengthB
     , elemB
+    , notElemB
 
     -- * Mutable Bloom filters
     -- ** Creation
@@ -219,6 +220,13 @@
 elemB elt ub = all test (hashesU ub elt)
   where test (off :* bit) = (bitArrayB ub `unsafeAt` off) .&. (1 `shiftL` bit) /= 0
           
+-- | Query an immutable Bloom filter for non-membership.  If the value
+-- /is/ present, return @False@.  If the value is not present, there
+-- is /still/ some possibility that @False@ will be returned.
+notElemB :: a -> Bloom a -> Bool
+notElemB elt ub = any test (hashesU ub elt)
+  where test (off :* bit) = (bitArrayB ub `unsafeAt` off) .&. (1 `shiftL` bit) == 0
+
 -- | Create an immutable Bloom filter from a mutable one.  The mutable
 -- filter /must not/ be modified afterwards, or a runtime crash may
 -- occur.  For a safer creation interface, use 'createB'.
diff --git a/Data/BloomFilter/Easy.hs b/Data/BloomFilter/Easy.hs
--- a/Data/BloomFilter/Easy.hs
+++ b/Data/BloomFilter/Easy.hs
@@ -17,6 +17,7 @@
       Bloom
     , easyList
     , elemB
+    , notElemB
     , lengthB
 
     -- ** Example: a spell checker
@@ -26,7 +27,7 @@
     , suggestSizing
     ) where
 
-import Data.BloomFilter (Bloom, elemB, fromListB, lengthB)
+import Data.BloomFilter (Bloom, elemB, fromListB, lengthB, notElemB)
 import Data.BloomFilter.Hash (Hashable, cheapHashes)
 import Data.BloomFilter.Util (nextPowerOfTwo)
 import qualified Data.ByteString as SB
diff --git a/bloomfilter.cabal b/bloomfilter.cabal
--- a/bloomfilter.cabal
+++ b/bloomfilter.cabal
@@ -1,5 +1,5 @@
 name:            bloomfilter
-version:         1.0
+version:         1.0.1
 license:         BSD3
 license-file:    LICENSE
 author:          Bryan O'Sullivan <bos@serpentine.com>
diff --git a/examples/SpellChecker.hs b/examples/SpellChecker.hs
--- a/examples/SpellChecker.hs
+++ b/examples/SpellChecker.hs
@@ -1,7 +1,5 @@
-import Data.BloomFilter.Easy (easyList, elemB)
+import Data.BloomFilter.Easy (easyList, notElemB)
 
 main = do
   filt <- (easyList 0.01 . words) `fmap` readFile "/usr/share/dict/words"
-  let check word | word `elemB` filt = ""
-                 | otherwise         = word ++ "\n"
-  interact (concat . map check . lines)
+  interact (unlines . filter (`notElemB` filt) . lines)
diff --git a/examples/Words.hs b/examples/Words.hs
--- a/examples/Words.hs
+++ b/examples/Words.hs
@@ -3,11 +3,23 @@
 -- queries it exhaustively.
 
 import Control.Monad (forM_, mapM_)
-import Data.BloomFilter.Easy (easyList, elemB, lengthB)
+import Data.BloomFilter (Bloom, fromListB, elemB, lengthB)
+import Data.BloomFilter.Hash (cheapHashes)
+import Data.BloomFilter.Easy (easyList, suggestSizing)
 import qualified Data.ByteString.Char8 as B
 import Data.Time.Clock (diffUTCTime, getCurrentTime)
 import System.Environment (getArgs)
 
+conservative, aggressive :: Double -> [B.ByteString] -> Bloom B.ByteString
+conservative = easyList
+
+aggressive fpr xs
+    = let (size, numHashes) = suggestSizing (length xs) fpr
+          k = 3
+      in fromListB (cheapHashes (numHashes - k)) (size * k) xs
+
+testFunction = aggressive
+
 main = do
   args <- getArgs
   let files | null args = ["/usr/share/dict/words"]
@@ -18,7 +30,7 @@
     putStrLn $ {-# SCC "words/length" #-} show (length words) ++ " words"
     b <- getCurrentTime
     putStrLn $ show (diffUTCTime b a) ++ "s to count words"
-    let filt = {-# SCC "construct" #-} easyList 0.01 words
+    let filt = {-# SCC "construct" #-} testFunction 0.01 words
     print filt
     c <- getCurrentTime
     putStrLn $ show (diffUTCTime c b) ++ "s to construct filter"
