[EMAIL PROTECTED] (Marcin 'Qrczak' Kowalczyk) wrote,

[..]
> The drawback of marsh* is that calls are not uniform. Sometimes
> marsh* are not needed, sometimes they are not sufficient (with array
> and its length passed as separate arguments), initial arguments are
> simpler to pass by partial application than by (return x :> forget),
> and in effect various calls look differently, each using a different
> shortcut. I have no presise idea how to make them better, sorry,
> but I believe it's possible. It could be good if they imposed
> little visual overhead for cases they do nothing special, like for
> (return x :> forget). And still be as simple as possible (but no more).

The `marsh*' family is an attempt to come up with an as
uniform as possible way to express a wide range of common
marshalling situations in pure Haskell.  It has to cope with 
the following problems:

* Some arguments need IO operations for marshalling.
* Most foreign calls are themselves IO operations.
* Some arguments need pre-processing, some prost-processing, 
  and some both.
* The pre- and post-processing can be quite different for
  different types, but there are many common operations
  (like allocating a container to pass as a pointer
  argument).

For a single argument of fixed type, it is not too
difficult - eg for `String's:

  marshString        :: (Addr -> IO a) -> String -> IO a
  marshString str op  =
    do
      addr <- stringToAddr str
      op addr
      free addr

which we use as in

  newWindow `marshString` "My window"

Unfortunately, this function is of no use if there is more
than one argument that requires marshalling - the IO monad
kills compositionality here.

Nevertheless, we can generalise this a little:

  type MarshSpec a ca = (a -> IO ca, ca -> IO ())

  marsh                    :: MarshSpec a ca -> a -> (ca -> IO b) -> IO b
  marsh (pre, post) arg op  =
    do
      carg <- pre arg
      op carg
      post carg

  string :: MarshSpec
  string  = (stringToAddr, free)

which we use as in

  newWindow `marsh` string $ "My window"

Now, we can provide a family of such `marsh' functions
(marhs1, marhs2, etc) for handling external functions that
require the marshalling of 1, 2, etc arguments.  With a
little more generalisation, we can also handle inout
parameters - the result is basically the code contained in
the C2HS marshalling library.

I am sure it is possible to improve the use of the library
by providing shortcuts for things like (return x :> forget).
I am happy to incorporate them, just let me know what you
think are the most common patterns.

I am not so sure whether it is possible to `radically'
improve the design, however.  Nevertheless, I may have
missed something and I would be most happy about good
suggestions.  Please remember that this is not only a C->HS
issue.  We plan to have a Haskell marshalling library to
simplify coding bindings on the plain FFI and there we have
exactly the same problems - so, the design of the library
matters beyond C->Haskell.

I have set up a page

  http://www.cse.unsw.edu.au/~chak/haskell/c2hs/lib/

with the latest library code for anybody interested in
having a look.

Sven, you might want to link to the above page from the "FFI
proposal page" (instead of the, I think, older versions of
the modules that you are linking at the moment).

Cheers,
Manuel

Reply via email to