→ Script-fu In GIMP 2.4
GIMP 2.4のScript-Fu
バージョン1.0のGimpからずっと、プログラマーの可能性を拡張させて繰り返し作業を単純化させるスクリプト言語が入っていました。このプログラミング言語"Script-Fu"はSchemeプログラミング言語の実装であるSIODインタプリタをベースに作られていました。SIODは80年代にボストン大学の教授であるGeorge J. Carretteによって作られました。
このScript-FuインタプリタはCarrette氏のSIODをベースとしていましたが、この10年間実によくGimpの役に立ってくれました -- そして数多くのスクリプトがGimpユーザーによって書き上げられ、共有されてきました -- しかしもう歳を召してしまったこともあり、Gimp開発者チームはTinySchemeというもっと近代的なSchemeインタプリタと交換することに決めたのです。この置き換えのもっとも大きな理由の一つは、SIODでは規定されていなかった言語やフォントの国際化に対応するためでした。他にも理由がありますが、国際化対応は最も重要なことだったわけです。
これによりGimp開発者(特にKevin Cozens氏)に広範囲な努力が求められ、Gimpソースコードの中身にはいくつかの重要な変更がなされ、Gimpユーザーにはちょっとだけ目に見える変更がありました。Gimpのスクリプト拡張はまだ"Script-Fu"と呼ばれており、利用可能な圧倒的多数のスクリプトは既に新しいTinySchemeベースのインタプリタで使われている機能になっています。
Gimp内部に対する変更による影響をできる限り最小限に抑えようとしたため、SIODベースのインタプリタとTinySchemeベースのインタプリタとの間にはいくつかの違いが生じてしまいました。それはGimp 2.4より古いスクリプトを使おうとすると出てくるかもしれません。以下は、遭遇するかもしれない問題についての説明と、それを修正するためにはどの手順を踏めばよいのかの説明です。
- 未宣言変数の扱い (Error: set!: unbound variable: x)
- 条件式における空リスト
- 空リストの最初の要素へのアクセス (Error: car: argument 1 must be: pair)
- リストの最終要素を超えるアクセス (Error: cdr: argument 1 must be: pair)
- ペアを作成 (Error: cons: needs 2 argument(s))
- 推奨されない機能
- 最後に (他の違い)
未宣言変数の扱い
古いスクリプトを使おうとするとよく遭遇する問題は、最初に変数を宣言することなく変数に値を割り当ててしまうことかもしれません。SIODベースのScript-Fuでは'x'が宣言されていなくても(set! x 4)といった構文が使用できていました。'x'が自動的にグローバル変数として定義されるようになっていたからです。新しいScript-Fuではこのような状況を保護します。プログラマーはまず最初に変数を宣言しなければいけません。問題のあるスクリプトでは"Error: set!: unbound variable: x"というメッセージが表示されるでしょう。
普通はグローバル変数を使うようなことはしないでおきましょう。なぜなら(別の作者によって書かれた)別の関数が同じ名前を使用してしまうと、その二つの関数はお互いに干渉してしまうからです。このため、先ほどの例での'x'を正しく宣言する方法は、letかlet*構文を使うことです。
(let* ( (x 4) )
...
...
...
)
条件式における空リスト
(if, while, cond, not, =, などの)条件判定においてSIODは空リストをFALSEとして扱います。一方Schemeの標準仕様ではこれをTRUEと評価します。プログラマーは最初からこの違いに気付いていて、SIOD非標準規格のスクリプトになることを残念に思っていました。しかしこれは可能であったのです。簡単な解決方法はリストをテストするために 'pair?' 関数を使用することです。例えば (while lis ... ) を (while (pair? lis) ...) に置き換えます。(pair? lis) は (not (null? lis)) に置き換えられます。
空リストの先頭要素にアクセス
SIODでは、空リストを'car'で取り出すと空リストを返しました。TinySchemeにおいてこれは許可されず、エラーメッセージ ("Error: car: argument 1 must be: pair") が作成されます。こういった条件文のように、プログラマーはSIOD非準拠の挙動に気を付けなければいけません。この問題に遭遇することはレアケースにならなくてはいけません。この問題を直すには、もし遭遇したら、リストにアクセスする前にリストが空であるかどうかの構成テストが必要です。
リストの最後尾要素より後ろにアクセス
前の問題に似ていますが、SIODはリストの最終要素を超えた要素にアクセスすることが許されており、このときには空リストが返されます。例えば、要素を持たないリストから'cdr'や'cddr'で取り出すことができました。Gimp 2.4ではこれを行うとエラーメッセージ ("Error: cdr: argument 1 must be: pair") となります。繰り返しになりますが、SIODの挙動は長い間ずっと非標準の挙動をしていて、この問題によりこういったレアな問題を発生させていました。この問題を修正するには、もし遭遇したら、リストにアクセスするときにはより正確なテストをしなければなりません。
ペアを作る
Schemeのcons関数はペアへと結合させる二つの引数を必要とします。SIODでは、引数が一つだけしかなかった場合には二番目の引数は自動的に空リストであるとみなされていました。Gimp 2.4では、二番目の引数が存在しなかった場合にはエラー ("Error: cons: needs 2 argument(s)") となります。解決するには、この問題が発生したら、第二引数として明示的に空リストを追加します。
推奨されない機能
次のSIOD関数や定数は現在のTinySchemeで使用することはできますが、将来のバージョンでは消えてしまうかもしれません。
aset- TinySchemeのvector-set!で置き換えaref- TinySchemeのvector-refで置き換えfopen- TinySchemeのopen-input-fileで置き換えmapcar- TinySchemeのmapで置き換えnil- TinySchemeの'()で置き換えnreverse- TinySchemeのreverseで置き換えpow- TinySchemeのexptで置き換えprin1- TinySchemeのwriteで置き換えprint- TinySchemeのwrite(newlineに続けて) で置き換えstrcat- TinySchemeのstring-appendで置き換えstring-lessp- TinySchemeのstring<?で置き換えsymbol-bound?- TinySchemeのdefined?で置き換えthe-environment- TinySchemeのcurrent-environmentで置き換え*pi*- 定数 *pi* はTinySchemeにおいて定義済ではありませんが(* 4 (atan 1.0))で定義することができますbutlast- TinySchemeで使用することはできませんが別コード(reverse (cdr (reverse x)))が利用可能ですcons-array- TinySchemeのmake-vectorで置き換え
最後に
もとのScript-FuとGimp 2.4のScript-Fuの間にはいくつかの違いがありますが、それらはレアケースであるため既存のスクリプトでそれほど大きな問題にはならないでしょう。catch/throw 文(これはエラーを捕捉する)と bytes-append 関数(これは世に出回っているScript-Fuの中には見られない)といった構文も違いに含まれます。そういった問題が含まれているスクリプトに遭遇したら、Gimp開発者メーリングリストへ問題の要旨について投稿してみてください。

ここの記事にリンク張らせてもらいました。