
Hi all, I have wrapped, using FFI, a C-library I am writing that calls into different programming languages. I put everything in the IO monad. So far it works as expected but I find the resulting usage code somewhat ugly (especially the bits musing 'sequence'). I tried using finalizers to delete the resources but it couldn't respect my dependencies. Can anyone offer any advice on making it feel more natural in Haskell? Note: The FFI code is available here: http://svn.solucorp.qc.ca/repos/solucorp/mlp/trunk/lib/haskell/ import qualified MLP import qualified MLP.Error import qualified MLP.Context import qualified MLP.Language import qualified MLP.Runtime import qualified MLP.Value import qualified MLP.Object main = do ctx <- MLP.Context.new -- create a context MLP.Context.with ctx $ do lang <- MLP.Language.init ctx "perl" -- init a language, i.e. perl rt <- MLP.Runtime.new ctx lang -- create a runtime for the language MLP.Runtime.loadLibrary ctx rt "calc" -- load a library, i.e. calc.pm val <- MLP.Object.new ctx rt "calc" [] "" -- create a calc object, i.e. my $obj = new calc() ; obj <- MLP.Value.takeObject val -- extract the object from the value MLP.Value.delete ctx val args_add <- sequence [MLP.Value.newLong 2, MLP.Value.newLong 3] args_mul <- sequence [MLP.Value.newDouble 3.5, MLP.Value.newDouble 4.6] val_add <- MLP.Object.callMethod ctx rt obj "add" args_add "" sequence $ map (MLP.Value.delete ctx) args_add val_mul <- MLP.Object.callMethod ctx rt obj "mul" args_mul "" sequence $ map (MLP.Value.delete ctx) args_mul MLP.Object.delete ctx obj MLP.Value.getLong val_add >>= putStrLn . show >> MLP.Value.delete ctx val_add MLP.Value.getDouble val_mul >>= putStrLn . show >> MLP.Value.delete ctx val_mul MLP.Runtime.delete ctx rt MLP.Language.delete ctx lang Thanks, Patrick -- ===================== Patrick LeBoutillier Rosemère, Québec, Canada

Hi Patrick One thing you can do is use `bracket` to manage the lifetime of objects created on the C side: withNewThing :: Init_param1 -> Init_param2 -> (Thing -> IO a) -> IO a withNewThing param1 param2 funAction = bracket (newThing param1 param2) destroyThing (\thing -> do { check_null <- isNullThing thing ; if check_null then do -- SOME FAILURE -- else funAction face }) -- newThing destroyThing isNullThing are defined somewhere. This might be appropriate for the Context, Language etc. objects in your library. For the documentation on bracket see Control.Exception.Base. Best wishes Stephen

Apologies - typo in copy pasted code - the last line should have been
else funAction thing
withNewThing :: Init_param1 -> Init_param2 -> (Thing -> IO a) -> IO a
withNewThing param1 param2 funAction =
bracket (newThing param1 param2) destroyThing
(\thing -> do { check_null <- isNullThing thing
; if check_null
then do -- SOME FAILURE --
else funAction thing })
2009/12/1 Stephen Tetley
withNewThing :: Init_param1 -> Init_param2 -> (Thing -> IO a) -> IO a withNewThing param1 param2 funAction = bracket (newThing param1 param2) destroyThing (\thing -> do { check_null <- isNullThing thing ; if check_null then do -- SOME FAILURE -- else funAction face })
participants (2)
-
Patrick LeBoutillier
-
Stephen Tetley