C functions with callbacks

Many C libraries such as Tcl_Tk require callback functions to be passed as their arguments. In SML#, you can just pass your own SML# functions directly. Moreover, argument functions can be higher-order.

This file contains (somewhat artificial) example C functions that take higher-order function and return higher-order functions. Among them are the following:

void f1(void(*f)(void(*)(void(*)(void(*)(void(*)(void(*)(void)))))))
void (*(*(*g1(void))(void))(void))(void)

In SML# type system, they corresponds restectively below:

f1 : (((((unit -> unit) -> unit) -> unit) -> unit) -> unit) -> unit
g1 : unit-> unit -> unit -> unit -> unit

So, you can simply call them by writing the following simple SML# code:

 val lib = DynamicLink.dlopen "./callback.so"
 val sym1 = DynamicLink.dlsym (lib, "f1")
 val sym2 = DynamicLink.dlsym (lib, "g1")
 val f1 = sym1 : _import (((((()->unit)->unit)->unit)->unit)->unit)->unit
 val g1 = sym2 : _import ()->()->()->()->unit

 val () =
     f1 (fn h1 =>
            (print "h1\n";
             h1 (fn h2 =>
                    (print "h2\n";
                     h2 (fn h3 =>
                            print "h3\n")))))

 val g2 = g1 ()
 val g3 = g2 ()
 val g4 = g3 ()
 val () = g4 ()

The following is the result of evaluation.

 $ gcc -shared -o callback.so callback.c
 $ smlsharp
 SML# 0.10 (2007-03-17 11:39:26)
 use "callback.sml";
 # val lib = 0x083e11d0 : unit ptr
 val sym1 = 0x4515489c : unit ptr
 val sym2 = 0x45154916 : unit ptr
 val f1 =
     fn : (((((unit  -> unit)  -> unit)  -> unit)  -> unit)  -> unit)  -> unit
 val g1 = fn : unit  -> unit  -> unit  -> unit  -> unit
 f1
 h1
 f2
 h2
 f3
 h3
 g1
 val g2 = fn : unit  -> unit  -> unit  -> unit
 g2
 val g3 = fn : unit  -> unit  -> unit
 g3
 val g4 = fn : unit  -> unit
 g4
 #
Last modified:2007/07/05 02:38:17
Keyword(s):
References:[Seamless Interoperability with C] [Program Examples]