packages feed

call-haskell-from-anything 0.2.0.0 → 1.0.0.0

raw patch · 5 files changed

+27/−113 lines, 5 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

- FFI.Anything.TypeUncurry.DataKinds: Proxy :: Proxy k
- FFI.Anything.TypeUncurry.DataKinds: data Proxy k
- FFI.Anything.TypeUncurry.DataKinds: instance FFI.Anything.TypeUncurry.DataKinds.ToTypeList (Data.Functor.Identity.Identity r) '[] r
- FFI.Anything.TypeUncurry.ReturnResult: return1 :: (Monad m) => r -> m r
- FFI.Anything.TypeUncurry.ReturnResult: return2 :: (Monad m) => (a -> r) -> a -> m r
- FFI.Anything.TypeUncurry.ReturnResult: return3 :: (Monad m) => (a -> b -> r) -> a -> b -> m r
- FFI.Anything.TypeUncurry.ReturnResult: return4 :: (Monad m) => (a -> b -> c -> r) -> a -> b -> c -> m r
- FFI.Anything.TypeUncurry.ReturnResult: return5 :: (Monad m) => (a -> b -> c -> d -> r) -> a -> b -> c -> d -> m r
- FFI.Anything.TypeUncurry.ReturnResult: return6 :: (Monad m) => (a -> b -> c -> d -> e -> r) -> a -> b -> c -> d -> e -> m r
- FFI.Anything.TypeUncurry.ReturnResult: return7 :: (Monad m) => (a -> b -> c -> d -> e -> f -> r) -> a -> b -> c -> d -> e -> f -> m r
- FFI.Anything.TypeUncurry.ReturnResult: returnId1 :: r -> Identity r
- FFI.Anything.TypeUncurry.ReturnResult: returnId2 :: (a -> r) -> a -> Identity r
- FFI.Anything.TypeUncurry.ReturnResult: returnId3 :: (a -> b -> r) -> a -> b -> Identity r
- FFI.Anything.TypeUncurry.ReturnResult: returnId4 :: (a -> b -> c -> r) -> a -> b -> c -> Identity r
- FFI.Anything.TypeUncurry.ReturnResult: returnId5 :: (a -> b -> c -> d -> r) -> a -> b -> c -> d -> Identity r
- FFI.Anything.TypeUncurry.ReturnResult: returnId6 :: (a -> b -> c -> d -> e -> r) -> a -> b -> c -> d -> e -> Identity r
- FFI.Anything.TypeUncurry.ReturnResult: returnId7 :: (a -> b -> c -> d -> e -> f -> r) -> a -> b -> c -> d -> e -> f -> Identity r
+ FFI.Anything.TypeUncurry.DataKinds: instance (FFI.Anything.TypeUncurry.DataKinds.Param f ~ '[], FFI.Anything.TypeUncurry.DataKinds.Result f ~ r, f ~ r) => FFI.Anything.TypeUncurry.DataKinds.ToTypeList f '[] r

Files

call-haskell-from-anything.cabal view
@@ -1,5 +1,5 @@ name:          call-haskell-from-anything-version:       0.2.0.0+version:       1.0.0.0 license:       MIT author:        Niklas Hambüchen (mail@nh2.me) maintainer:    Niklas Hambüchen (mail@nh2.me)@@ -34,7 +34,6 @@   exposed-modules:     FFI.Anything.TH     FFI.Anything.TypeUncurry-    FFI.Anything.TypeUncurry.ReturnResult     FFI.Anything.TypeUncurry.Msgpack     FFI.Anything.TypeUncurry.DataKinds   build-depends:
src/FFI/Anything/TypeUncurry/DataKinds.hs view
@@ -12,28 +12,11 @@ -- 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'+-- and then use 'translate' 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.DataKinds where -import           Control.Monad.Identity+import           Data.Proxy   -- * Type-level lists (containing types)@@ -72,18 +55,15 @@ -}  -- | 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) = '[]-type instance Param (IO r) = '[]-type instance Param (a -> f) = a ': Param f+type family Param f :: [*] where+  Param (a -> f) = a ': Param f+  Param r = '[]  -- | 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+type family Result f :: * where+  Result (IO r) = IO r+  Result (a -> f) = Result f+  Result r = r   -- | Function f can be translated to 'TypeList' l with result type r.@@ -94,25 +74,28 @@   -- Example: @t1 -> ... -> tn -> r@ becomes @TypeList [t1, ..., tn] -> r@.   translate :: f -> TypeList l -> r --- | Recursive case: A function of type @a -> ... -> r@--- can be translated to @TypeList [a, ...] -> r@.-instance ToTypeList (Identity r) '[] r where-  translate (Identity r) Nil = r --- | Base case: A "pure" function without arguments (just @Identity r@)+-- | Base case: A "pure" function without arguments -- can be translated to @TypeList Nil -> r@. instance (ToTypeList f l r) => ToTypeList (a -> f) (a ': l) r where   translate f (a ::: l) = translate (f a) l --- | Base case: An IO function without arguments (just @Identity r@)+-- | Base case: An IO function without arguments (just @IO r@) -- can be translated to @TypeList Nil -> r@. instance ToTypeList (IO r) '[] (IO r) where   translate ior Nil = ior +-- | Base case: A value @r@ can be translated to @TypeList Nil -> r@.+instance (Param f ~ '[], Result f ~ r, f ~ r) => ToTypeList f '[] r where+  -- Could also be written as+  --   (Param r ~ '[], Result r ~ r) => ToTypeList r '[] r+  -- but I find the other way clearer.+  translate r Nil = r + -- Now an example: ----- someFunction :: Int -> Double -> Identity String+-- someFunction :: Int -> Double -> String -- someFunction _i _d = return "asdf" -- -- exampleAutoTranslate = translate someFunction@@ -122,24 +105,17 @@  -- * 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 :: Proxy l)   paramLength :: Proxy l -> Int  instance ParamLength '[] where   paramLength _ = 0  instance (ParamLength l) => ParamLength (a ': l) where-  paramLength _ = succ $ paramLength (undefined :: Proxy l)-+  paramLength _ = succ $ paramLength (Proxy :: Proxy l)
src/FFI/Anything/TypeUncurry/Msgpack.hs view
@@ -27,7 +27,6 @@ , byteStringToCStringFunIO , export , exportIO-, module FFI.Anything.TypeUncurry.ReturnResult ) where  import           Data.ByteString (ByteString)@@ -35,12 +34,11 @@ import qualified Data.ByteString.Lazy as BSL import           Data.Maybe (fromMaybe) import qualified Data.MessagePack as MSG+import           Data.Proxy import           Data.Vector (Vector) import qualified Data.Vector as V import           Foreign.C -import FFI.Anything.TypeUncurry.ReturnResult- import FFI.Anything.TypeUncurry  @@ -79,7 +77,7 @@ 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+-- | Translates a function of type @a -> b -> ... -> r@ to -- a function that: -- -- * takes as a single argument a 'ByteString' containing all arguments serialized in a MessagePack array@@ -139,7 +137,7 @@   return res_cs  --- | Exports a "pure" function (usually it has to be wrapped in the Identity monad)+-- | Exports a "pure" function -- to an FFI function that takes its arguments as a serialized MessagePack message. -- -- Calling this function throws an 'error' if the de-serialization of the arguments fails!
− src/FFI/Anything/TypeUncurry/ReturnResult.hs
@@ -1,48 +0,0 @@-module FFI.Anything.TypeUncurry.ReturnResult where--import Control.Monad.Identity---return1 :: (Monad m) => r -> m r-return1 = return--return2 :: (Monad m) => (a -> r) -> a -> m r-return2 f a = return $ f a--return3 :: (Monad m) => (a -> b -> r) -> a -> b -> m r-return3 f a b = return $ f a b--return4 :: (Monad m) => (a -> b -> c -> r) -> a -> b -> c -> m r-return4 f a b c = return $ f a b c--return5 :: (Monad m) => (a -> b -> c -> d -> r) -> a -> b -> c -> d -> m r-return5 f a b c d = return $ f a b c d--return6 :: (Monad m) => (a -> b -> c -> d -> e -> r) -> a -> b -> c -> d -> e -> m r-return6 f a b c d e = return $ f a b c d e--return7 :: (Monad m) => (a -> b -> c -> d -> e -> f -> r) -> a -> b -> c -> d -> e -> f -> m r-return7 f a b c d e = return . f a b c d e -- We don't want to use f again, haha!---returnId1 :: r -> Identity r-returnId1 = return1--returnId2 :: (a -> r) -> a -> Identity r-returnId2 = return2--returnId3 :: (a -> b -> r) -> a -> b -> Identity r-returnId3 = return3--returnId4 :: (a -> b -> c -> r) -> a -> b -> c -> Identity r-returnId4 = return4--returnId5 :: (a -> b -> c -> d -> r) -> a -> b -> c -> d -> Identity r-returnId5 = return5--returnId6 :: (a -> b -> c -> d -> e -> r) -> a -> b -> c -> d -> e -> Identity r-returnId6 = return6--returnId7 :: (a -> b -> c -> d -> e -> f -> r) -> a -> b -> c -> d -> e -> f -> Identity r-returnId7 = return7-
test/Test1.hs view
@@ -6,9 +6,7 @@ import           Data.ByteString (ByteString) import qualified Data.ByteString as BS import qualified Data.ByteString.Lazy as BSL-import           Data.Monoid import qualified Data.MessagePack as MSG-import           Control.Monad.Identity  import Foreign.C @@ -41,17 +39,8 @@     return res_cs  -f1_identity :: Int -> Double -> Identity String-f1_identity a b = return $ f1 a b----- Only works in GHC 7.6--- f1_t :: CString -> IO CString--- f1_t :: ByteString -> ByteString--- f1_t = translateCall f1_identity- f1_t :: ByteString -> ByteString-f1_t = uncurryMsgpack f1_identity+f1_t = uncurryMsgpack f1  foreign export ccall f1_t_export :: CString -> IO CString f1_t_export :: CString -> IO CString@@ -73,7 +62,7 @@  foreign export ccall fib_export :: CString -> IO CString fib_export :: CString -> IO CString-fib_export = export . returnId2 $ fib+fib_export = export fib   -- TODO the sole *presence* of this function seems to make the calls in Python slower