SML# - Resources/ProgrammingExamples/CallBack Diff

  • Added parts are displayed like this.
  • Deleted parts are displayed like this.

tcl/tkなど多くのライブラリは,コールバック関数を必用とする.
SML#では,単にSML#の関数を引数に渡すだけでコールバック関数を実現でき
る.さらに,コールバック関数は高階の関数であってもよい.

[[callbackサンプル|smlsharp:examples/callback/callback.c]]は,高階の関数を受け取る
Cの関数定義の例である.この中の関数
void f1(void(*f)(void(*)(void(*)(void(*)(void(*)(void(*)(void)))))));
void (*(*(*g1(void))(void))(void))(void);
は,MLではそれぞれ以下のような型の関数に対応する.
f1 : (((((unit -> unit) -> unit) -> unit) -> unit) -> unit) -> unit
g1 : unit-> unit -> unit -> unit -> unit
そこで,これらの関数を以下のように使うことができる.
  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 ()
このコードをSML#で評価すると,期待通の以下のような結果が得られる.
  $ 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
  #