[MLton-user] Calling C functions with a variable number of
arguments
Phil Clayton
phil.clayton at lineone.net
Thu Sep 2 05:32:04 PDT 2010
Thanks for the update on MLton. I suspected it would be harder than I
thought to support varargs.
I hadn't considered encapsulating a finite number of calling signatures
in a structure. That should work well for my short-term practical
needs. Most vararg C functions I will be calling have very restricted
argument patterns, unlike e.g. printf, so the number of cases should not
grow too fast, if not actually linear in the number of varargs.
Phil
Matthew Fluet wrote:
> On Tue, Aug 31, 2010 at 9:21 AM, Phil Clayton <phil.clayton at lineone.net> wrote:
>> Thanks for the link - I read with great interest. I would like to explore
>> NLFFI further but in the short term I am tied to using MLton's _import
>> directly.
>>
>> To get a feel what direction I should be heading in, it would be useful to
>> known whether there are any plans afoot to support varargs for _import -
>> just variability up to compile-time, not at run-time.
>
> There are no immediate plans to support varargs for _import. I think
> that It would require a fairly serious reworking of the type checker
> in order to support varargs for _import.
>
>> The capability appears almost there in MLton: we can already write e.g.
>>
>> val fa = _import "f" : t -> unit;
>> val fb = _import "f" : t * b2 -> unit;
>> val fc = _import "f" : t * c2 * c1 -> unit;
>>
>> i.e. any number of different calling signatures to the C function f and use
>> fa, fb, fc, etc. as required.
>
> That's true. And it is probably the best approach. If you can
> enumerate (or automatically generate) a suitably large number of
> distinct _import expressions, then you could probably hide them in a
> module, require the user to perform the injection into the 'arg' type
> and then dispatch to the correct _import expression:
>
> structure FVarArg :
> sig
> datatype arg = SChar of Int8.int | UChar of Word8.word | ... |
> Double of Real64.real
> val f : arg list -> unit
> end =
> struct
> datatype arg = SChar of Int8.int | UChar of Word8.word | ... |
> Double of Real64.real
> fun f [] = (_import "f" : unit -> unit) ()
> | f [SChar a1] = (_import "f" : Int8.int -> unit) (a1)
> | f [UChar a1] = (_import "f" : Word8.word -> unit) (a1)
> ...
> | f [Double a1] = (_import "f" : Real64.real -> unit) (a1)
> | f [SChar a1, SChar a2] = (_import "f" : Int8.int * Int8.int ->
> unit) (a1, a2)
> | f [SChar a1, UChar a2] = (_import "f" : Int8.int * Word8.word ->
> unit) (a1, a2)
> ...
> | f [SChar a1, Double a2] = (_import "f" : Int8.int * Real64.real
> -> unit) (a1, a2)
> ...
> | f _ => raise Fail "Unsupported argument list."
> end
>
> Of course, this suffers from a combinatorial explosion in code size,
> and will always be limited to a finite number of possible argument
> lists.
>
> You could combine this with the Danvy-style typings technique
> discussed in the ml-varargs paper to get a more palatable interface.
>
>> In order to provide general purpose libraries that don't tie down the number
>> of arguments (until compile-time), it would be nice to be able to write e.g.
>>
>> val f = _import "f" : t -> ... -> unit;
>>
>> and just use f, letting type inference fill in the types of the missing
>> curried arguments. That could be awkward as '...' can't be represented by a
>> type variable, so perhaps e.g.
>>
>> val f = _import "f" : t -> 'a -> unit;
>>
>> where 'a must be a nested tuple, e.g. bool * (real * (int * unit)).
>
> It's trickier than that. The type checker requires _import have a
> ground type --- no type variables, and, furthermore, that all of the
> types are types compatible with the C interface (e.g., no tuple or
> datatype types). It is also trickier because for each distinct
> instantiation of such a varargs _import, we would need to introduce a
> new ground _import. (That is very different than what happens when a
> standard HM-polymorphic value is instantiated.)
>
>> With an eye to constructing type safe interfaces (as described in John et
>> al.'s paper, section 3), it is is worth noting that it is easy to convert
>> such a function on nested pairs to have curried arguments:
>>
>> fun curry f x y = f (x, y)
>> fun na x = x (* no arg *)
>> fun va f g = f o curry g (* var arg *)
>> fun va_call spec = spec (fn f => f ())
>>
>> Then we have
>>
>> va_call na; (* (unit -> 'a) -> 'a *)
>> va_call va; (* ('b * unit -> 'a) -> 'b -> 'a *)
>> va_call (va o va);
>> (* ('c * ('b * unit) -> 'a) -> 'c -> 'b -> 'a *)
>> va_call (va o va o va);
>> (* ... *)
>> etc.
>>
>> (Here the last argument has type unit as there could be no arguments.)
>>
>> Phil
>>
>>
>> John Reppy wrote:
>>> We support varargs in SML/NJ using a technique described in a 2008 ML
>>> Workshop
>>> paper. A key feature of our approach is that it should be possible to use
>>> our
>>> implementation in any ML system that supports C calls. You can find a
>>> copy of
>>> the paper at
>>>
>>> http://people.cs.uchicago.edu/~jhr/papers/2008/ml-varargs.pdf
>>>
>>> On Jul 26, 2010, at 2:00 PM, mlton-user-request at mlton.org wrote:
>>>> Hi,
>>>>
>>>> I have been using the FFI and have found it very flexible but have run
>>>> into a problem that I can't see how to solve. I am trying to call a C
>>>> function with a variable number of arguments but need the variability in the
>>>> number of arguments available in SML too.
>>>>
>>>> The attached examples show that there is no problem importing a C
>>>> function with a variable argument list for a fixed number of arguments: the
>>>> files 'call_sum_<N>.sml' import the C function 'sum' with N arguments for
>>>> the variable argument list. I need to do something like
>>>>
>>>> val sum = _import "sum" : int * int list -> int;
>>>>
>>>> (I am happy for the variable arguments to have the same type in SML.)
>>>> Does anyone have any ideas about how to achieve a similar effect?
>>>>
>>>> Thanks,
>>>> Phil
>>>
>>
>>
>>
>> _______________________________________________
>> MLton-user mailing list
>> MLton-user at mlton.org
>> http://mlton.org/mailman/listinfo/mlton-user
>>
>
More information about the MLton-user
mailing list