diff --git a/Data/PerfectHash.lhs b/Data/PerfectHash.lhs
--- a/Data/PerfectHash.lhs
+++ b/Data/PerfectHash.lhs
@@ -1,4 +1,4 @@
-> {-# LANGUAGE ForeignFunctionInterface, ScopedTypeVariables, EmptyDataDecls, BangPatterns #-}
+> {-# LANGUAGE ForeignFunctionInterface, ScopedTypeVariables, EmptyDataDecls, BangPatterns, TypeSynonymInstances, FlexibleInstances #-}
 > module Data.PerfectHash ( PerfectHash, fromList, lookup, lookupByIndex ) where
 
 > import Array
@@ -12,9 +12,11 @@
 > import qualified Data.ByteString.Char8 as S
 > import qualified Data.ByteString.Unsafe as Unsafe
 > import Data.Array.Storable
+> import Data.Binary
 > import Data.Digest.CRC32 (crc32)
 > import Data.Digest.Adler32 (adler32)
-> import Control.Monad(guard)
+> import Control.Monad(guard, liftM)
+> import GHC.Arr (unsafeAt)
  
 Arguably the FFI stuff should be in a separate file, but let's keep it simple for the moment.
 
@@ -28,64 +30,94 @@
 > data ForeignHash
 
 > data PerfectHash a = PerfectHash { store     :: !(Array.Array Word32 (a,CString)),
->                                    hashFunc  :: !(S.ByteString -> Word32) }
+>                                    cmph      :: Ptr ForeignHash 
+>                                  }
 
-pretty certain this could be improved
+is this even a sane thing to do?
 
-> use_hash a str = {-# SCC "use_hash" #-}  unsafePerformIO $ Unsafe.unsafeUseAsCStringLen str
->                  (\(cstr,i) -> return (fromIntegral $ c_cmph_search a cstr (fromIntegral i)))
+-- > instance Binary CString where
+-- >     get = undefined
+-- >     put (s :: CString) = undefined
 
-> raw_hashfunc hash cstr len = fromIntegral $ c_cmph_search hash cstr len
+-- > instance (Binary a) => Binary (PerfectHash a) where
+-- >     get = do
+-- >           size <- get
+-- >           arr <- newArray_ (0,size)
+-- >           forM_ [0 .. size] $ writeArray arr 
+-- >           store <- get
+-- >           cmph <- undefined
+-- >           return $ PerfectHash { store = store, cmph = cmph }
+-- >     put p = do
+-- >             let arr = store p
+-- >                 last = rangeSize (bounds arr) - 1
+-- >             put last
+-- >             mapM_ (\(a, str) -> put a >> put (unsafePerformIO $ S.packCString str))
+-- >                       [ unsafeAt arr i | i <- [0 .. last] ]
 
+-- >             put (cmph p)
+
+-- > instance Binary (Ptr ForeignHash) where
+-- >     get = undefined
+-- >     put f = undefined
+
+> raw_hashfunc hash (cstr,len) = fromIntegral $ c_cmph_search hash cstr (fromIntegral len)
+
 This could do with being broken up a little, probably
 
+
 > fromList :: Show a => [(S.ByteString, a)] -> PerfectHash a
 > fromList ls = unsafePerformIO $ do
->                   let len = length ls
->                   arr <- newArray_ (0, len-1)
+>                   (fodder,cstr_ptrs) <- prepareCPtrs
+>                   cmph <- withStorableArray fodder $ \ptr -> c_build_hash ptr (fromIntegral len)
+>                   i_arr <- buildArray cmph cstr_ptrs
+>                   return PerfectHash { store = i_arr, 
+>                                        cmph = cmph }
+
+>   where prepareCPtrs = do 
+>                   fodder <- newArray_ (0, len-1)
 >                   -- we make one pass over ls, then throw it away
 >                   cstr_ptrs <- mapM (\(i,(bs, val)) ->
 >                          S.useAsCStringLen bs $ \(cstr,len) -> do
 >                            newPtr <- c_strdup cstr
->                            writeArray arr i newPtr
->                            return (newPtr,fromIntegral len,val))
+>                            writeArray fodder i newPtr
+>                            return ((newPtr,fromIntegral len),val))
 >                         (zip [0..] ls)
->                   cmph <- withStorableArray arr $ \ptr -> c_build_hash ptr (fromIntegral len)
->                   let bounds :: (Word32, Word32) = (fromIntegral 0, fromIntegral len - 1)
->                   arr <- newArray_ bounds :: IO (IOArray Word32 a)
->                   checksums <- newArray_ bounds :: IO (IOArray Word32 Word32)
->                   let hashFunc = use_hash cmph
->                   mapM_ (\(cstr,len,val) -> do
->                          let index = raw_hashfunc cmph cstr len
->                          writeArray arr index (val,cstr)) $ cstr_ptrs
->                   i_arr <- freeze arr
->                   return PerfectHash { store = i_arr, 
->                                        hashFunc = use_hash cmph }
-
->                 
-
--- > crc = crc32
-
--- > crc = adler32
+>                   return (fodder, cstr_ptrs)
+>                          
+>         buildArray cmph cstr_ptrs = do
+>                   arr <- newArray_ (fromIntegral 0, fromIntegral len - 1) :: IO (IOArray Word32 a)
+>                   mapM_ (\(cl@(cstr,len),val) -> writeArray arr (raw_hashfunc cmph cl) (val,cstr)) $ cstr_ptrs
+>                   -- we created it, we can do what we like with it...
+>                   unsafeFreeze arr
+>                                
+>         len = length ls
 
 > lookup :: PerfectHash a -> S.ByteString -> Maybe a
-> lookup !hash !bs
->     | check     = Just e
->     | otherwise = Nothing
->     where index = {-# SCC "hash_only" #-} hashFunc hash bs
+> lookup !hash !bs = guard check >> return e
+>     where index = {-# SCC "hash_only" #-} use_hash (cmph hash) bs
 >           (!low, !high) = Array.bounds arr
 >           !arr = store hash
 >           (e, str) = arr ! index
+
+basic index checking stuff plus a check that we haven't just had a hash collision - tried crc checking here
+and it turns out that strncmp is faster
+
 >           !check = {-# SCC "check" #-} low <= index && high >= index && 
 >                   {-# SCC "bs_check" #-} unsafePerformIO $ Unsafe.unsafeUseAsCStringLen bs (\(cstr,len) -> 
 >                                               c_strncmp str cstr (fromIntegral len) >>= \res -> return (res == 0))
 
+>           use_hash a str = {-# SCC "use_hash" #-}  unsafePerformIO $ Unsafe.unsafeUseAsCStringLen str
+>                            (return . raw_hashfunc a)
+
+
+
+
 sometimes it's convenient to have direct access, but this should probably be seen as a
 slightly devious use case.
 
 > lookupByIndex :: PerfectHash a -> Word32 -> Maybe S.ByteString
 > lookupByIndex hash index = do
 >                guard $ low <= index && high >= index
->                return $ unsafePerformIO $ S.packCString $ snd $  arr ! index
+>                return $ unsafePerformIO $ S.packCString $ snd $ unsafeAt arr (fromIntegral index)
 >   where (!low, !high) = bounds arr
 >         arr = store hash
diff --git a/PerfectHash.cabal b/PerfectHash.cabal
--- a/PerfectHash.cabal
+++ b/PerfectHash.cabal
@@ -1,5 +1,5 @@
 Name:           PerfectHash
-Version:        0.1
+Version:        0.1.1
 Cabal-Version:  >= 1.2
 License:	BSD3
 License-File:   LICENSE
@@ -23,7 +23,7 @@
         includes: stub.h
         extra-lib-dirs: /usr/local/lib/
         extra-libraries: cmph
-        build-depends:  base, haskell98, containers, bytestring, digest,array, time
+        build-depends:  base, haskell98, containers, bytestring, digest,array, time, binary
 
 Executable benchmark
         Executable:     benchmark
