[ocaml-ctypes] Best practices for wrapping ocaml-ctypes?

Jeremy Yallop yallop at gmail.com
Tue Aug 11 10:41:28 BST 2015


On 10/08/2015, Andi McClure <andi.m.mcclure at gmail.com> wrote:
> The syntax could use some work :P But never mind that. I've so far got it
> where when you invoke ffi.c.function, the function specification you
> provided gets piped into OCaml and turned into this OCaml data structure:
>
>     type foreignSpec = { name : string; args : string list; returning:
> string; }
>
> This seems like a straightforward representation of the information @->
> encodes; it seems something parsing a header would need to represent the
> data the same way.
>
> My naive impulse is to imagine that this is straightforward, and I need to
> just build up a typ variable by repeatedly chaining @->, something like:
>
>     let typeConvert = function "void" -> void | "int" -> int | _ ->
> failwith "??"

Right: it should be possible to do things like that once you've dealt
with the typing problem you describe.

The easiest approach to dealing with the fact that 'int', 'void', etc.
have different types is to use an existential type.  Existential types
in OCaml are a sort of variant, but defined with a different syntax;
instead of writing something like this:

   type t = A of x
          | B of y

you give the type signature for each constructor, like this:

   type t = A : x -> t
          | B : y -> t

By itself that doesn't give you any extra power, and you can actually
write any variant type definition this way.  The distinctive feature
of existential types is that you can mention type variables on the
right of the '=' that don't appear in the type parameters on the left.
Here's an example:

   type ty = Ty : 'a Ctypes.typ -> ty

As the type signature says, 'Ty' takes a value of type 'a Ctypes.typ'
for any type 'a' and builds a value of type 'ty'.  You can therefore
use 'Ty' to wrap Ctypes.typ values of different types up as 'ty'
values.  For example, you can build a list of typs:

   # [Ty void; Ty int];;
   - : ty list = [Ty void; Ty int]

and you can wrap the variously-typed results of your 'typeConvert'
function so that they all have the same type 'ty':

   let typeConvert = function
       "void" -> Ty void
     | "int" -> Ty int
     | _ -> failwith "??"

The same difficulty arises with 'Ctypes.fn' and your 'functionFrom'
definition, which needs to build function type descriptions of all
sorts of different types.  Here's a second existential type which
wraps 'Ctypes.fn':

   type fn = Fn : ('a -> 'b) Ctypes.fn -> fn

This time the type signature says that 'Fn' takes a value of type '(a
-> b) Ctypes.fn' for any types 'a' and 'b' and builds a value of type
'fn'.  It should be possible to build something like 'functionFrom'
that wraps and unwraps intermediate values using 'Ty' and 'Fn' to deal
with the immediate typing problems (leaving the interesting question
of how to turn the function returned by 'Foreign.foreign' into
something that can be called from your interpreter).

I hope that helps a bit.

Kind regards,

Jeremy.


More information about the Ctypes mailing list