2011年5月8日日曜日

Racket、tinyscheme、Gaucheでローカル変数、ローカル関数を使ってみたメモ

やりたいこと:
GimpのScript-Fuでなるべくグローバル関数やグローバル変数を使わないで処理を行ないたいということ(他のスクリプトとバッティングするとイヤなので)。
で、ローカル関数は再帰的に呼び出したい場合がけっこうある。

開発環境:
GimpのScript-Fuを開発するのに、RacketやEmacsを使っている。

Racketは、IDEとして便利だが、Gimpを直接呼べない(方法を知らないだけ?)
Emacsは、script-fu-shell.rb(http://haraita9283.blog98.fc2.com/blog-entry-323.html)を使うと、Gimpと対話的に開発ができる。
で、Gimpでは、tinyschemeを内部的に使っている。
また、Schemeの勉強をするのにGaucheを使っている。

課題:
Schemeの処理系(Racket、tinyscheme、Gauche)によって、挙動が異なるところがあり、今回、けっこうはまった。

対応のメモ:
Racket、tinyscheme、Gaucheで、ローカル変数とローカル関数を使うのに、以下のようにしてみた。
Scheme初心者なので間違っているかもしれないが、とりあえずメモ。

1.ローカル変数とローカル関数の宣言にはletrecの変数の束縛部を使う。
ローカル関数を再帰的に使うにはletrecを使う必要がある。
ローカル変数を宣言するのに、letrecの式の実行部でdefineを使い、順番に参照させるとうまくいかない処理系がある。

2.ローカル変数の値の初期化は、letrecの式の実行部でset!を使う。
厳密には値を初期化とは言わないと思う。
letrecの変数の束縛部では、変数に順番に代入ができない。
そこで、letrecの変数の束縛部ではとりあえず#fとかの値を束縛させておく。
letrecの式の実行部でset!を使って、値を設定していく。

3.set-car!やset-cdr!は使わない。
set-car!などの挙動が処理系によって異なる。
consを使って、リストを組み立て直し、set!で設定する。セルを無駄遣いしているかも。

具体例:

(define グローバル関数名
(lambda (引数1 引数2 ...)
(letrec
(
;; ローカル変数やローカル関数の束縛部
(ローカル変数名 #f)
(ローカル変数名 #f)
...
(ローカル関数名
(lambda (引数1 引数2 ...)
ローカル関数の処理内容))
(ローカル関数名
(lambda (引数1 引数2 ...)
ローカル関数の処理内容))
...
)
;; グローバル関数の式の実行部
(set! ローカル変数1 設定したい内容)
(set! ローカル変数2 設定したい内容)
...
グローバル関数の処理内容)))

0 件のコメント: