2008/3/13 の comp.lang.scheme

Gambit-C's FFI and variadic functions - comp.lang.scheme

質問

Gambit-C の ncurses バインディングを書いているんだけど Gambit-C の FFI では printw のような Variadic function はサポートされないんだ。
どうしたらよいだろう?


(注)Variadic という単語が分からなくて調べたら見つかりました。可変長引数の関数のことでした。

, a variadic function is a function of variable arity; that is, one which can take different numbers of arguments.

回答

Scheme は強い value typed、これに対して C は 弱い variable typed なので、Cの可変長引数へのバインディングを安全に提供するのは難しい。(実行時のコストがかかるし安全でない)
だから Scheme で以下のように実装するのはどうだろう?

(printw-int    an-int)   --> printw("%d",an-int);
(printw-float  a-float)  --> printw("%f",a-float);
(printw-string a-string) --> printw("%s",a-string);

(define (printw fmt . args)
  (let loop
      ((chunks (parse-printw-fmt fmt))
       ;; (parse-printw-fmt "abc %d def %s ghi %f klm")
       ;; --> ("abc " #<fmt-integer> " def " #<fmt-string>
       ;;     " ghi " #<fmt-float> " klm")
       (args   args)
       (if (null? chunks)
           (if (null? args)
               'nil
               (error "Too many args"))
           (loop (rest chunks)
                 (let ((item (first chunks))
                       (arg  (first args)))
                   (cond
                    ((string? item)
                     (printw-string item)
                     args)
                    ((fmt-string?  item)
                     (if (string? arg)
                         (printw-string arg)
                         (error "%s expects a string argument"))
                     (rest args))
                    ((fmt-integer? item)
                     (if (integer? arg)
                         (printw-integer arg)
                         (error "%d expects an integer argument"))
                     (rest args))
                    ((fmt-float?   item)
                     (if (float? arg)
                         (printw-float arg)
                         (error "%f expects a float argument"))
                     (rest args))
                    ...)))))))

(感想)FFIの話は個人的にタイムリーだ。回答者の指摘の通り、実行時に渡された値の Scheme 上での型を調べて C が期待する型に変換するのは難しそう。

(蛇足)ここ数日の comp.lang.scheme を見ていると Stalin ってのが割と使われているコンパイラなのかな。