SML# - Resources/ProgrammingExamples/Qsort Diff

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

C言語のライブラリ関数qsort(3)も,[[fread(3)同様の多相関数|Resources/ProgrammingExamples/PolyC]]である.
マニュアルによれば,その型は以下の通りである.
  void qsort(void *base, size_t nmemb, size_t size,
             int(*compar)(const void *, const void *));
各引数の意味は以下の通りである.
* voild *base:ソート対象配列
* size_t nmemb :配列の要素の数
* size_t size :配列の要素のサイズ
* int(*compar)(const void *, const void *):要素へのポインタの組みを受け取る比較関数
MLのような型付き多相型言語では以下のような関数として使用できるのが望ま
しい.
qsort : 'a array * ('a ptr * 'a ptr -> int) -> unit
ここで,'a ptrはCの空間にある'a型へのポインタである.
SML#では,
[[コールバック機能|Resources/ProgrammingExamples/CallBack]]

[[freadの場合|Resources/ProgrammingExamples/PolyC]]
と同様の考え方を使い,以下のように使用することができる.
  val libc = DynamicLink.dlopen "/lib/libc.so.6"
  val c_qsort = DynamicLink.dlsym (libc, "qsort")
  fun qsort (a, f) =
      _ffiapply c_qsort (a : 'a array,
                         Array.length a : int,
                         _sizeof('a),
                         f : ('a ptr, 'a ptr) -> int) : unit
この式をSML#で評価すると,実際に
val qsort = fn : ['a .'a Array.array * ('a ptr * 'a ptr  -> int)  -> unit]
の結果が得られる.この関数を使用するためには,Cの領域にあるオブジェクトの比較関数を定義する必用がある.
そのために,以下の多重定義関数が用意されている.
!! : ['a::{int, real, word, byte, char}.'a ptr -> 'a]
これを使い,たとえば以下のように呼び出すことができる.
  fun compareReal (p1, p2) =
      let
        val n1 = !!p1 : real
        val n2 = !!p2
      in
        if n1 > n2 then 1 else if n1 < n2 then ~1 else 0
      end
  val _ = qsort (aRealArray, compareReal)