Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way to chain functions like withCString?

Is there a way to chain functions like withCString? By that I mean any function that looks something like f :: Foo -> (CFoo -> IO a) -> IO a.

For example, lets say there is a function cFunc :: CString -> CFoo -> CBar -> IO ()

Usualy, I would do something like:

haskellFunc string foo bar =
  withCString string $ \ cString ->
    withCFoo foo $ \ cFoo ->
      withCBar bar $ \ cBar ->
        cFunc cString cFoo cBar

But i would like to do something like:

haskellFunc = (withCString |.| withCFoo |.| withCBar) cFunc

with some appropriate composition operator |.|.

I'm writing library with a lot of C bindings, and this boilerplate comes often. Am I doing something wrong?

like image 552
ivokosir Avatar asked May 22 '16 21:05

ivokosir


1 Answers

You can use the Continuation applicative for composing these a -> (b -> IO c) -> IO c functions:

import Control.Monad.Cont

haskellFunc :: String -> Foo -> Bar -> IO ()
haskellFunc string foo bar = flip runCont id $ 
    cFunc <$> 
      cont (withCString string) <*> 
      cont (withCFoo foo) <*> 
      cont (withCBar bar)

Or with a bit of extra syntax:

haskellFunc' :: String -> Foo -> Bar -> IO ()
haskellFunc' string foo bar = flip runCont id $
    cFunc <<$>> withCString string <<*>> withCFoo foo <<*>> withCBar bar
  where
    f <<$>> x = f <$> cont x
    f <<*>> x = f <*> cont x
like image 151
Cactus Avatar answered Oct 19 '22 21:10

Cactus