トップ > Script-Fuスクリプトの制作 >
プログラミング言語Schemeの基礎を学ぶ(その4)

  

プログラミング言語Schemeの基礎(続き)

前の記事の『プログラミング言語Schemeの基礎を学ぶ(その3)』からの続きです。 引き続き、Script-Fuスクリプトを制作するにあたって知っておくべきSchemeの基礎について解説します。

この記事では、複数の情報を扱うための "ベクタ" (vector) について解説します。 複数の情報を扱うという意味では前の記事で登場したリストに似ていますが、こちらの方が扱いは楽です。

  
"vector" を "ベクトル" と表記しているウェブサイトも多いです。 どちらも正しいですが、本ウェブサイトでは "ベクタ" と表記しています。

ベクタとは

ベクタとは、リストと同じように複数の情報が並んだものです。 例えば従業員の情報を表すベクタであれば、

  1. 高見 登
  2. 石上 三年
  3. 薄井 幸子

のように氏名がズラッと並んだものがベクタになります。 でも、上の一覧を見て『リストと同じじゃないか』と思った方も多いことでしょう。

複数の情報を扱える、という意味ではベクタとリストはとても似ています。 しかし、内部での取り扱いは全く異なります。 リストの場合は、

- 最初のコンスセル -
car部 "高見 登"と書かれた紙が置かれている場所
cdr部 <2つ目のコンスセルの場所>
- 2つ目のコンスセル -
car部 "石上 三年"と書かれた紙が置かれている場所
cdr部 <3つ目のコンスセルの場所>
- 3つ目のコンスセル -
car部 "薄井 幸子"と書かれた紙が置かれている場所
cdr部 <空っぽ>

のように、見えない紐で3つのコンスセルがつながったような構造をしています。

一方、ベクタは、

1) 高見 登
2) 石上 三年
3) 薄井 幸子

のように、まとめて1つのデータとして扱われます。 ベクタでは、複数の情報でも1つのデータとして扱えるのです

ベクタを使ってみる

では、実際にベクタを利用してみましょう。 スクリプトファイル myscript.scm を以下のように修正してください。

  1. (define (myscript)
  2. (let*
  3. (
  4. (outnumber 9)
  5. (innumber (vector 90 80))
  6. )

  7. (set! outnumber (myfunc-addnumber (vector-ref innumber 0) (vector-ref innumber 1)))

  8. (gimp-message (string-append "Number is " (number->string outnumber)))
  9. )
  10. )

  11. (define (myfunc-addnumber x y)
  12. (+ x y)
  13. )

  14. (script-fu-register
  15. "myscript" ; 登録する関数の名前
  16. "My Script" ; メニュー項目のラベル
  17. "自作の練習用スクリプトです" ; メニュー項目の説明
  18. "My Name" ; 作成者の名前
  19. "My Name" ; 著作権者の名前
  20. "January 1, 2023" ; 作成日(改訂日)
  21. "" ; メニュー項目を有効にするための条件
  22. )

  23. (script-fu-menu-register
  24. "myscript" ; 対象の関数の名前
  25. "<Image>/Filters" ; メニュー項目の位置
  26. )
 

修正箇所は2箇所です。 1箇所目は5行目で、

(innumber  (cons 10 (list 20 30)))

を、

(innumber  (vector 90 80))

に変更しています。 リストを作成する場合には手続き listを使用していましたが、ベクタの作成では手続き vectorを使います

手続き vectorによって作られたベクタは、変数 innumberの初期値として格納されます。 格納される初期値は以下の通りです。

1) 90
2) 80

修正箇所の2箇所目は8行目で、

(set! outnumber (myfunc-addnumber (car innumber) (cadr innumber)))

を、

(set! outnumber (myfunc-addnumber (vector-ref innumber 0) (vector-ref innumber 1)))

に変更しています。 変更前は手続き carで最初の情報を、手続き cadrで2番目の情報を取り出していましたが、変更後は新たな手続き vector-refが登場しています

手続き vector-ref

手続き vector-refは、指定された番号の情報をベクタから取り出すためのものです。 受け取る引数は2つで、最初の引数がベクタで、次の引数が取り出す情報の番号です。 なお、番号は 0(ゼロ) から始まります

今回のベクタの、

1) 90
2) 80

であれば、

(vector-ref innumber 0)

とすることで 90 が取り出され、

(vector-ref innumber 1)

とすれば 80 が取り出されます。 番号は 0(ゼロ) から始まるということを忘れないでください


では、実行してみましょう。

1. ウィンドウ下部に "Number is 170" と表示される
1. ウィンドウ下部に "Number is 170" と表示される

上図のようにウィンドウ下部に "Number is 170" と表示されます。 このように、リストに比べるとベクタでは情報を取り出すのはとても簡単です。

手続き vectorを使わずにベクタを作ってみよう

作成中のスクリプトでは、

(innumber  (vector 90 80))

のように、手続き vectorを利用してベクタを作成しました。 ここでは別の記述方法についても紹介しておきます

別の記述方法とは、

(innumber  #(90 80))

と記述することです。 前の記事で解説したリストの作成と通じるものがあります。 リストの作成も、

(list 1 2 3)

という記述を、

(quote (1 2 3))

と記述しても同じ結果となり、さらに、

'(1 2 3)

と省略して記述することもできました。

では、実際にこの別の記述方法でベクタを作成してみましょう。 スクリプトファイル myscript.scm を以下のように修正してください。

  1. (define (myscript)
  2. (let*
  3. (
  4. (outnumber 9)
  5. (innumber #(90 80))
  6. )

  7. (set! outnumber (myfunc-addnumber (vector-ref innumber 0) (vector-ref innumber 1)))

  8. (gimp-message (string-append "Number is " (number->string outnumber)))
  9. )
  10. )

  11. (define (myfunc-addnumber x y)
  12. (+ x y)
  13. )

  14. (script-fu-register
  15. "myscript" ; 登録する関数の名前
  16. "My Script" ; メニュー項目のラベル
  17. "自作の練習用スクリプトです" ; メニュー項目の説明
  18. "My Name" ; 作成者の名前
  19. "My Name" ; 著作権者の名前
  20. "January 1, 2023" ; 作成日(改訂日)
  21. "" ; メニュー項目を有効にするための条件
  22. )

  23. (script-fu-menu-register
  24. "myscript" ; 対象の関数の名前
  25. "<Image>/Filters" ; メニュー項目の位置
  26. )
 

では、実行してみましょう。

1. ウィンドウ下部に "Number is 170" と表示される
1. ウィンドウ下部に "Number is 170" と表示される

上図のようにウィンドウ下部に "Number is 170" と表示されます。 修正前と同じ結果です。

このように、

(vector 90 80)

という記述は、

#(90 80)

と記述することもできます。

手続き vector-lengthでベクタの情報件数を取得してみよう

ではここで、新たな手続き vector-lengthについて紹介しておきます。 Script-Fuスクリプトを制作する上で欠かせないとても大切な手続きです

手続き vector-lengthはベクタの中の情報の件数を取得するためもので、

1) 高見 登
2) 石上 三年
3) 薄井 幸子

というベクタであれば結果は 3 となります。

では、実際に手続き vector-lengthを使ってみましょう。 スクリプトファイル myscript.scm を以下のように修正します。

  1. (define (myscript)
  2. (let*
  3. (
  4. (outnumber 9)
  5. (innumber #(90 80))
  6. )

  7. (set! outnumber (myfunc-addnumber (vector-ref innumber 0) (vector-ref innumber 1)))

  8. (gimp-message (string-append "Summary of " (number->string (vector-length innumber)) " Numbers is " (number->string outnumber)))
  9. )
  10. )

  11. (define (myfunc-addnumber x y)
  12. (+ x y)
  13. )

  14. (script-fu-register
  15. "myscript" ; 登録する関数の名前
  16. "My Script" ; メニュー項目のラベル
  17. "自作の練習用スクリプトです" ; メニュー項目の説明
  18. "My Name" ; 作成者の名前
  19. "My Name" ; 著作権者の名前
  20. "January 1, 2023" ; 作成日(改訂日)
  21. "" ; メニュー項目を有効にするための条件
  22. )

  23. (script-fu-menu-register
  24. "myscript" ; 対象の関数の名前
  25. "<Image>/Filters" ; メニュー項目の位置
  26. )
 

修正箇所は10行目で、

(gimp-message (string-append "Number is " (number->string outnumber)))

を、

(gimp-message (string-append "Summary of " (number->string (vector-length innumber)) " Numbers is " (number->string outnumber)))

に変更しています。 表示するメッセージの中に加算した数値の件数も含めるように修正しています。

では、実行してみましょう。

1. ウィンドウ下部に "Summary of 2 Numbers is 170" と表示される
1. ウィンドウ下部に "Summary of 2 Numbers is 170" と表示される

上図のようにウィンドウ下部に "Summary of 2 Numbers is 170" と表示されます。 2つの数値が加算されたこともメッセージに含めることができました。

このように、手続き vector-lengthを利用することでベクタの情報件数を取得することができます。

次の記事へ

長くなってきましたので、そろそろ一区切りします。 続きは次の記事を参照ください

  
  

まとめ

ベクタとは、複数の情報を1つのデータとして扱うための仕組みです。 新たにベクタを作成するには、手続き vectorを使います。 なお、省略して #(1 2 3) のように記述することもできます。

手続き 説明
vector ベクタを作成する

ベクタから情報を取り出すには手続き vector-refを使います。 最初の引数がベクタで、次の引数が取り出す情報の番号です。 番号は 0(ゼロ) から始まります。

手続き 説明
vector-ref ベクタから情報を1件取り出す

また、手続き vector-lengthを利用することでベクタの情報件数を取得することができます。

手続き 説明
vector-length ベクタの情報件数を取得する
メニュー