diff --git a/Setup.hs b/Setup.hs
--- a/Setup.hs
+++ b/Setup.hs
@@ -1,2 +1,2 @@
 import Distribution.Simple
-main = defaultMain
+main = defaultMainWithHooks autoconfUserHooks
diff --git a/call-haskell-from-anything.cabal b/call-haskell-from-anything.cabal
--- a/call-haskell-from-anything.cabal
+++ b/call-haskell-from-anything.cabal
@@ -1,5 +1,5 @@
 name:          call-haskell-from-anything
-version:       0.1.0.2
+version:       0.2.0.0
 license:       MIT
 author:        Niklas Hambüchen (mail@nh2.me)
 maintainer:    Niklas Hambüchen (mail@nh2.me)
@@ -8,9 +8,10 @@
 -- See the ./configure script.
 build-type:    Configure
 license:       MIT
-synopsis:      Python-to-Haskell function calls
+synopsis:      Call Haskell functions from other languages via serialization and dynamic libraries
+description:   FFI via serialisation. See https://github.com/nh2/call-haskell-from-anything for details.
 stability:     experimental
-tested-with:   GHC==7.6.3, GHC==7.8.2
+tested-with:   GHC==7.10.3
 cabal-version: >= 1.10
 homepage:      https://github.com/nh2/call-haskell-from-anything
 bug-reports:   https://github.com/nh2/call-haskell-from-anything/issues
@@ -32,23 +33,17 @@
     src
   exposed-modules:
     FFI.Anything.TH
-    FFI.Anything.Copied
     FFI.Anything.TypeUncurry
     FFI.Anything.TypeUncurry.ReturnResult
-    FFI.Anything.TypeUncurry.Legacy
     FFI.Anything.TypeUncurry.Msgpack
-  if impl(ghc >= 7.6.0)
-    exposed-modules:
-      FFI.Anything.TypeUncurry.DataKinds
-  other-modules:
-    FFI.Anything.Util
+    FFI.Anything.TypeUncurry.DataKinds
   build-depends:
-      base >= 4 && < 5
+      base >= 4.8 && < 5
     , bytestring >= 0.10.0.0
-    , msgpack >= 0.7.1.5 && < 1.0.0
+    , msgpack >= 1.0.0
     , template-haskell
     , mtl >= 2.1.2
-    , attoparsec >= 0.10.3.0
+    , vector
   ghc-options:
     -Wall -fwarn-unused-imports
 
diff --git a/src/FFI/Anything/Copied.hs b/src/FFI/Anything/Copied.hs
deleted file mode 100644
--- a/src/FFI/Anything/Copied.hs
+++ /dev/null
@@ -1,61 +0,0 @@
--- | Contains some functions needed from the msgpack package
--- that are unfortunately not yet exposed.
---
--- See https://github.com/msgpack/msgpack-haskell/pull/34.
-module FFI.Anything.Copied where
-
-import           Data.ByteString.Lazy.Builder
-import qualified Data.Attoparsec.ByteString as A
-import           Data.Bits
-import           Data.Monoid
-import           Data.Word
-import           Text.Printf
-
-
--- Copied from Data.MessagePack.Pack
-fromArray :: (a -> Int) -> (a -> Builder) -> a -> Builder
-fromArray lf pf arr = do
-  case lf arr of
-    len | len <= 15 ->
-      word8 $ 0x90 .|. fromIntegral len
-    len | len < 0x10000 ->
-      word8 0xDC <>
-      word16BE (fromIntegral len)
-    len ->
-      word8 0xDD <>
-      word32BE (fromIntegral len)
-  <> pf arr
-
-
--- Copied from Data.MessagePack.Unpack
-parseArray :: (Int -> A.Parser a) -> A.Parser a
-parseArray aget = do
-  c <- A.anyWord8
-  case c of
-    _ | c .&. 0xF0 == 0x90 ->
-      aget . fromIntegral $ c .&. 0x0F
-    0xDC ->
-      aget . fromIntegral =<< parseUint16
-    0xDD ->
-      aget . fromIntegral =<< parseUint32
-    _ ->
-      fail $ printf "invalid array tag: 0x%02X" c
-
-
-parseUint16 :: A.Parser Word16
-parseUint16 = do
-  b0 <- A.anyWord8
-  b1 <- A.anyWord8
-  return $ (fromIntegral b0 `shiftL` 8) .|. fromIntegral b1
-
-
-parseUint32 :: A.Parser Word32
-parseUint32 = do
-  b0 <- A.anyWord8
-  b1 <- A.anyWord8
-  b2 <- A.anyWord8
-  b3 <- A.anyWord8
-  return $ (fromIntegral b0 `shiftL` 24) .|.
-           (fromIntegral b1 `shiftL` 16) .|.
-           (fromIntegral b2 `shiftL` 8) .|.
-           fromIntegral b3
diff --git a/src/FFI/Anything/TypeUncurry.hs b/src/FFI/Anything/TypeUncurry.hs
--- a/src/FFI/Anything/TypeUncurry.hs
+++ b/src/FFI/Anything/TypeUncurry.hs
@@ -1,30 +1,10 @@
-{-# LANGUAGE CPP #-}
-
-#if MIN_VERSION_base(4,6,0)
-#define USE_DATA_KINDS 1
-#endif
-
-#if USE_DATA_KINDS
 {-# LANGUAGE DataKinds, TypeOperators #-}
-#endif
 {-# LANGUAGE TypeOperators, ScopedTypeVariables, FlexibleContexts #-}
 
--- | For GHC 7.6 or newer, we use (and re-export) "FFI.Anything.TypeUncurry.DataKinds" which uses DataKinds for TypeList to be kind-safe.
---
--- For all other versions, use (and re-export) "FFI.Anything.TypeUncurry.Legacy" which uses a simpler model of TypeList.
 module FFI.Anything.TypeUncurry (
-#if USE_DATA_KINDS
   -- | You see this because your compiler supports DataKinds.
   module FFI.Anything.TypeUncurry.DataKinds
-#else
-  -- | You see this because your compiler does not support DataKinds.
-  module FFI.Anything.TypeUncurry.Legacy
-#endif
 ) where
 
 
-#if USE_DATA_KINDS
 import FFI.Anything.TypeUncurry.DataKinds
-#else
-import FFI.Anything.TypeUncurry.Legacy
-#endif
diff --git a/src/FFI/Anything/TypeUncurry/Legacy.hs b/src/FFI/Anything/TypeUncurry/Legacy.hs
deleted file mode 100644
--- a/src/FFI/Anything/TypeUncurry/Legacy.hs
+++ /dev/null
@@ -1,129 +0,0 @@
-{-# LANGUAGE GADTs, TypeOperators, MultiParamTypeClasses, FlexibleInstances, TypeFamilies, ScopedTypeVariables, FlexibleContexts #-}
-
--- | Converts function arguments to tuple-like types.
---
--- This module is the LEGACY module not using DataKinds.
--- Compilers supporting DataKinds (e.g. GHC >= 7.6) should use "FFI.Anything.TypeUncurry".
---
--- For example, take @f :: a -> b -> c -> r@.
--- This module can convert it to @f' :: (a, b, c) -> r@, at compile time.
---
--- This is especially useful for (de)serialization.
--- Suppose you have a function that takes multiple arguments
--- and you want to obtain all of its arguments from some serialized data.
--- The serialization library will make it very easy to unpack types
--- like tuples/lists, but de-serializing *fuction arguments* is not that simple.
---
--- Using this module, you can write an instance how to unpack the 'TypeList' type,
--- and then use 'translateCall' to make any function take such a single 'TypeList'
--- instead of multiple function arguments.
---
--- There is currently a technical limitation:
--- The result type must be wrapped in the 'Identity' monad.
---
--- Example:
---
--- >-- Assume your library provides some unpack function, e.g. it allows you to write:
--- >unpack someBytestring :: (Int, String, Double)
--- >
--- >-- and you have a function
--- >f :: Int -> String -> Double -> Identity Char
--- >
--- >-- then you can use:
--- >f' :: (Int, String, Double) -> Identity Char
--- >f' = translateCall f
--- >
--- >result = f' (unpack someBytestring)
-module FFI.Anything.TypeUncurry.Legacy where
-
-import           Control.Monad.Identity
-
-
--- * Type-level lists (containing types)
-
--- | The empty type-level type list
-data Nil
--- | A type attached to a type-level type list
-data a ::: b
-
--- | Type-level list that can contain arbitrarily mixed types.
---
--- Example:
---
--- >1 ::: "hello" ::: 2.3 :: TypeList (Int ::: String ::: Double ::: Nil)
-data TypeList l where
-  Nil :: TypeList Nil
-  (:::) :: a -> TypeList l -> TypeList (a ::: l)
-
--- Right-associativity, like (->)
-infixr :::
-
-
--- * \"Uncurrying\" functions
-
-{- In the following, we try to not use Template Haskell,
-   using an instance of (a -> ...) to convert functions to TypeLists automatically
-   (similar to how you make variadic functions).
--}
-
--- | Arguments to a function, e.g. @[String, Int]@ for @String -> Int -> r@.
-type family Param f
--- | For pure functions, we need an 'Identity' monad wrapper here to not conflict with @a -> f@.
-type instance Param (Identity r) = Nil
-type instance Param (IO r) = Nil
-type instance Param (a -> f) = a ::: Param f
-
--- | The result of a function, e.g. @r@ for @String -> Int -> r@.
-type family Result f
--- | For pure functions, we need an 'Identity' monad wrapper here to not conflict with @a -> f@.
-type instance Result (Identity r) = r
-type instance Result (IO r) = IO r
-type instance Result (a -> f) = Result f
-
-
--- | Function f can be translated to 'TypeList' l with result type r.
-class (Param f ~ l, Result f ~ r) => ToTypeList f l r where
-  -- | Translates a function taking multiple arguments to a function
-  -- taking a single 'TypeList' containing the types of all arguments.
-  --
-  -- Example: @t1 -> ... -> tn -> r@ becomes @TypeList (t1 ::: ... ::: tn ::: Nil) -> r@.
-  translate :: f -> TypeList l -> r
-
--- | Recursive case: A "pure" function of type @a -> ... -> r@
--- can be translated to @TypeList (a ::: ...) -> r@.
-instance (ToTypeList f l r) => ToTypeList (a -> f) (a ::: l) r where
-  translate f (a ::: l) = translate (f a) l
-
--- | Base case: A "pure" function without arguments (just @Identity r@)
--- can be translated to @TypeList Nil -> r@.
-instance ToTypeList (Identity r) Nil r where
-  translate (Identity r) Nil = r
-
--- | Base case: An IO function without arguments (just @Identity r@)
--- can be translated to @TypeList Nil -> r@.
-instance ToTypeList (IO r) Nil (IO r) where
-  translate ior Nil = ior
-
-
--- * Length of type-level lists
-
--- | A proxy type that can contain an arbitrary type.
---
--- Needed for some type-level computations, like 'paramLength'.
-data Proxy k = Proxy
-
-
--- | Allows to calculate the length of a 'TypeList', at compile time.
---
--- We need to use a 'Proxy' for this.
-class ParamLength l where
-  -- | Calculates the length of a type list, put into a proxy. Usage:
-  --
-  -- >paramLength (undefined :: Proxy l)
-  paramLength :: Proxy l -> Int
-
-instance ParamLength Nil where
-  paramLength _ = 0
-
-instance (ParamLength l) => ParamLength (a ::: l) where
-  paramLength _ = succ $ paramLength (undefined :: Proxy l)
diff --git a/src/FFI/Anything/TypeUncurry/Msgpack.hs b/src/FFI/Anything/TypeUncurry/Msgpack.hs
--- a/src/FFI/Anything/TypeUncurry/Msgpack.hs
+++ b/src/FFI/Anything/TypeUncurry/Msgpack.hs
@@ -1,13 +1,6 @@
-{-# LANGUAGE CPP #-}
 {-# OPTIONS_GHC -fno-warn-orphans #-}
 
-#if MIN_VERSION_base(4,6,0)
-#define USE_DATA_KINDS 1
-#endif
-
-#if USE_DATA_KINDS
 {-# LANGUAGE DataKinds, TypeOperators #-}
-#endif
 {-# LANGUAGE TypeOperators, ScopedTypeVariables, FlexibleContexts #-}
 
 -- | Easy FFI via MessagePack.
@@ -25,7 +18,7 @@
 --
 -- * Expose Haskell functions via a socket / the web
 module FFI.Anything.TypeUncurry.Msgpack (
-  UnpackableRec (..)
+  MessagePackRec (..)
 , getTypeListFromMsgpackArray
 , uncurryMsgpack
 , tryUncurryMsgpack
@@ -37,61 +30,53 @@
 , module FFI.Anything.TypeUncurry.ReturnResult
 ) where
 
-import           Control.Applicative
-import qualified Data.Attoparsec.ByteString as A
 import           Data.ByteString (ByteString)
 import qualified Data.ByteString as BS
+import qualified Data.ByteString.Lazy as BSL
+import           Data.Maybe (fromMaybe)
 import qualified Data.MessagePack as MSG
+import           Data.Vector (Vector)
+import qualified Data.Vector as V
 import           Foreign.C
-import           Text.Printf
 
-import FFI.Anything.Copied
-import FFI.Anything.Util
 import FFI.Anything.TypeUncurry.ReturnResult
 
--- For GHC 7.6 or newer, this imports a TypeUncurry that uses DataKinds for TypeList to be kind-safe.
--- For older versions, it imports TypeUncurryLegacy which uses a weaker model of TypeList.
 import FFI.Anything.TypeUncurry
 
 
--- | Helper to allow writing a 'MSG.Unpackable' instance for 'TypeList's.
+-- | Helper to allow writing a 'MSG.MessagePack' instance for 'TypeList's.
 --
 -- We need this because we have to call 'parseArray' at the top-level
--- 'MSG.Unpackable' instance, but not at each function argument step.
-class UnpackableRec l where
-  getRec :: A.Parser (TypeList l)
+-- 'MSG.MessagePack' instance, but not at each function argument step.
+class MessagePackRec l where
+  fromObjectRec :: Vector MSG.Object -> Maybe (TypeList l)
 
 -- | When no more types need to be unpacked, we are done.
-#if USE_DATA_KINDS
-instance UnpackableRec '[] where -- For GHC 7.6 or newer, use DataKinds.
-#else
-instance UnpackableRec Nil where
-#endif
-  getRec = return Nil
+instance MessagePackRec '[] where
+  fromObjectRec v | V.null v = Just Nil
+  fromObjectRec _            = Nothing
 
 -- | Unpack one type by just parsing the next element.
-#if USE_DATA_KINDS
-instance (MSG.Unpackable a, UnpackableRec l) => UnpackableRec (a ': l) where  -- For GHC 7.6 or newer, use DataKinds.
-#else
-instance (MSG.Unpackable a, UnpackableRec l) => UnpackableRec (a ::: l) where
-#endif
-  getRec = (:::) <$> MSG.get <*> getRec
-
-
+instance (MSG.MessagePack a, MessagePackRec l) => MessagePackRec (a ': l) where
+  fromObjectRec v | not (V.null v) = (:::) <$> MSG.fromObject (V.head v) <*> fromObjectRec (V.tail v)
+  fromObjectRec _                  = Nothing
 
 -- | Parses a tuple of arbitrary size ('TypeList's) from a MessagePack array.
-getTypeListFromMsgpackArray :: forall l . (UnpackableRec l, ParamLength l) => A.Parser (TypeList l)
-getTypeListFromMsgpackArray = parseArray f
+getTypeListFromMsgpackArray :: forall l . (MessagePackRec l, ParamLength l) => MSG.Object -> Maybe (TypeList l)
+getTypeListFromMsgpackArray obj = case obj of
+    MSG.ObjectArray v | V.length v == len -> fromObjectRec v
+    _                                     -> Nothing
   where
     len = paramLength (Proxy :: Proxy l)
-    f n | n == len  = getRec
-        -- TODO also print function name
-        | otherwise = fail $ printf "getTypeListFromMsgpackArray: wrong number of function arguments: expected %d but got %d" len n
 
+instance (MessagePackRec l, ParamLength l) => MSG.MessagePack (TypeList l) where
+  fromObject = getTypeListFromMsgpackArray
+  toObject = error "call-haskell-from-anything: Serialising a TypeList is not supported (and not needed)!"
 
-instance (UnpackableRec l, ParamLength l) => MSG.Unpackable (TypeList l) where
-  get = getTypeListFromMsgpackArray
 
+-- | Standard error message when unpacking failed.
+errorMsg :: String -> String
+errorMsg locationStr = "call-haskell-from-anything: " ++ locationStr ++ ": got wrong number of function arguments or non-array"
 
 
 -- | Translates a function of type @a -> b -> ... -> Identity r@ to
@@ -103,32 +88,32 @@
 --
 -- This function throws an 'error' if the de-serialization of the arguments fails!
 -- It is recommended to use 'tryUncurryMsgpack' instead.
-uncurryMsgpack :: (MSG.Unpackable (TypeList l), ToTypeList f l r, MSG.Packable r) => f -> (ByteString -> ByteString)
-uncurryMsgpack f = \bs -> lazyToStrictBS . MSG.pack $ (translate f $ MSG.unpack bs)
+uncurryMsgpack :: (MSG.MessagePack (TypeList l), ToTypeList f l r, MSG.MessagePack r) => f -> (ByteString -> ByteString)
+uncurryMsgpack f = \bs -> BSL.toStrict . MSG.pack $ (translate f $ fromMaybe (error (errorMsg "uncurryMsgpack")) $ MSG.unpack $ BSL.fromStrict bs)
 
 
 -- | Like 'uncurryMsgpack', but for 'IO' functions.
 --
 -- This function throws an 'error' if the de-serialization of the arguments fails!
 -- It is recommended to use 'tryUncurryMsgpackIO' instead.
-uncurryMsgpackIO :: (MSG.Unpackable (TypeList l), ToTypeList f l (IO r), MSG.Packable r) => f -> (ByteString -> IO ByteString)
-uncurryMsgpackIO f = \bs -> lazyToStrictBS . MSG.pack <$> (translate f $ MSG.unpack bs)
+uncurryMsgpackIO :: (MSG.MessagePack (TypeList l), ToTypeList f l (IO r), MSG.MessagePack r) => f -> (ByteString -> IO ByteString)
+uncurryMsgpackIO f = \bs -> BSL.toStrict . MSG.pack <$> (translate f $ fromMaybe (error (errorMsg "uncurryMsgpackIO")) $ MSG.unpack $ BSL.fromStrict bs)
 
 
 -- | Like 'uncurryMsgpack', but makes it clear when the 'ByteString' containing
 -- the function arguments does not contain the right number/types of arguments.
-tryUncurryMsgpack :: (MSG.Unpackable (TypeList l), ToTypeList f l r, MSG.Packable r) => f -> (ByteString -> Either String ByteString)
-tryUncurryMsgpack f = \bs -> case MSG.tryUnpack bs of
-  Left e     -> Left e
-  Right args -> Right . lazyToStrictBS . MSG.pack $ (translate f $ args)
+tryUncurryMsgpack :: (MSG.MessagePack (TypeList l), ToTypeList f l r, MSG.MessagePack r) => f -> (ByteString -> Maybe ByteString)
+tryUncurryMsgpack f = \bs -> case MSG.unpack $ BSL.fromStrict bs of
+  Nothing   -> Nothing
+  Just args -> Just . BSL.toStrict . MSG.pack $ (translate f $ args)
 
 
 -- | Like 'uncurryMsgpack', but makes it clear when the 'ByteString' containing
 -- the function arguments does not contain the right number/types of arguments.
-tryUncurryMsgpackIO :: (MSG.Unpackable (TypeList l), ToTypeList f l (IO r), MSG.Packable r) => f -> (ByteString -> Either String (IO ByteString))
-tryUncurryMsgpackIO f = \bs -> case MSG.tryUnpack bs of
-  Left e     -> Left e
-  Right args -> Right $ lazyToStrictBS . MSG.pack <$> (translate f $ args)
+tryUncurryMsgpackIO :: (MSG.MessagePack (TypeList l), ToTypeList f l (IO r), MSG.MessagePack r) => f -> (ByteString -> Maybe (IO ByteString))
+tryUncurryMsgpackIO f = \bs -> case MSG.unpack $ BSL.fromStrict bs of
+  Nothing   -> Nothing
+  Just args -> Just $ BSL.toStrict . MSG.pack <$> (translate f $ args)
 
 
 -- * Exporting
@@ -159,7 +144,7 @@
 --
 -- Calling this function throws an 'error' if the de-serialization of the arguments fails!
 -- Use 'tryExport' if you want to handle this case.
-export :: (MSG.Unpackable (TypeList l), ToTypeList f l r, MSG.Packable r) => f -> CString -> IO CString
+export :: (MSG.MessagePack (TypeList l), ToTypeList f l r, MSG.MessagePack r) => f -> CString -> IO CString
 export = byteStringToCStringFun . uncurryMsgpack
 
 
@@ -167,7 +152,7 @@
 --
 -- Calling this function throws an 'error' if the de-serialization of the arguments fails!
 -- Use 'tryExportIO' if you want to handle this case.
-exportIO :: (MSG.Unpackable (TypeList l), ToTypeList f l (IO r), MSG.Packable r) => f -> CString -> IO CString
+exportIO :: (MSG.MessagePack (TypeList l), ToTypeList f l (IO r), MSG.MessagePack r) => f -> CString -> IO CString
 exportIO = byteStringToCStringFunIO . uncurryMsgpackIO
 
 
diff --git a/src/FFI/Anything/Util.hs b/src/FFI/Anything/Util.hs
deleted file mode 100644
--- a/src/FFI/Anything/Util.hs
+++ /dev/null
@@ -1,13 +0,0 @@
--- | Contains some helper functions.
-module FFI.Anything.Util (
-  lazyToStrictBS
-) where
-
-import           Data.ByteString (ByteString)
-import qualified Data.ByteString.Lazy as BSL
-import           Data.Monoid
-
-
--- | Could use Data.ByteString.Lazy.toStrict starting from bytestring 0.10.0.0
-lazyToStrictBS :: BSL.ByteString -> ByteString
-lazyToStrictBS = mconcat . BSL.toChunks
diff --git a/test/Test1.hs b/test/Test1.hs
--- a/test/Test1.hs
+++ b/test/Test1.hs
@@ -24,11 +24,11 @@
 
 -- To be translated to:
 f1' :: ByteString -> ByteString
-f1' bs = mconcat . BSL.toChunks $ MSG.pack (uncurry f1 $ msg)
+f1' bs = BSL.toStrict $ MSG.pack (uncurry f1 $ msg)
   where
-    msg = case MSG.tryUnpack bs of
-      Left e  -> error $ "tryUnpack: " ++ e
-      Right r -> r
+    msg = case MSG.unpack (BSL.fromStrict bs) of
+      Nothing -> error "could not unpack"
+      Just r -> r
 
 
 -- TODO check who deallocs - it seems to work magically!
