こんにちは、鈴木です。
「C言語からGaucheを使おう!」シリーズです。
「C言語からGaucheを使おう! (2) 基本的な値の生成」に続けて、今回はリストを操作する方法を調べます。
Scm_Cons 関数
Scm_Cons 関数は cons セルを生成します。
| 1 2 3 4 | ScmObj list; list = Scm_Cons(SCM_MAKE_INT(3), SCM_NIL); list = Scm_Cons(SCM_MAKE_INT(2), list); list = Scm_Cons(SCM_MAKE_INT(1), list); | 
このコードは、以下の Scheme コードと同じです。
| 1 | (cons 1 (cons 2 (cons 3 '()))) | 
以下のようにすると Scheme のコードと見た目が近くなります。
| 1 2 3 | Scm_Cons(SCM_MAKE_INT(1),          Scm_Cons(SCM_MAKE_INT(2),                   Scm_Cons(SCM_MAKE_INT(3), SCM_NIL))); | 
SCM_LISTn マクロ
要素数が 1 〜 5 のリストを手軽に作成するために、SCM_LIST1 〜 SCM_LIST5 というマクロも準備されています。
| 1 2 3 4 5 | #define SCM_LIST1(a)             Scm_Cons(a, SCM_NIL) #define SCM_LIST2(a,b)           Scm_Cons(a, SCM_LIST1(b)) #define SCM_LIST3(a,b,c)         Scm_Cons(a, SCM_LIST2(b, c)) #define SCM_LIST4(a,b,c,d)       Scm_Cons(a, SCM_LIST3(b, c, d)) #define SCM_LIST5(a,b,c,d,e)     Scm_Cons(a, SCM_LIST4(b, c, d, e)) | 
定義を見れば一目瞭然ですが、以下のように使用します。
| 1 | SCM_LIST3(SCM_MAKE_INT(1), SCM_MAKE_INT(2), SCM_MAKE_INT(3)); | 
構築するリストの要素数が固定である場合は、上記マクロを使用すると便利そうです。
Scm_List 関数
Scm_List 関数は、可変個の引数からリストを生成する関数です。
使い方は難しくありませんが、最後の引数として NULL を渡す必要があるので注意しましょう。
| 1 | Scm_List(SCM_MAKE_INT(3), SCM_MAKE_INT(2), SCM_MAKE_INT(1), NULL); | 
※補足ですが、C言語で可変個の引数を取る関数を作成する場合は、引数として「引数の数」を渡すか、最後の引数に NULL などの特定の値を渡すことが一般的です。Scm_List は後者の方法で、最後に NULL が渡される前提で実装されています。
リストの操作: Scm_Car, Scm_Cdr 関数
Scheme でリストを操作するときの基本は、car と cdr です。
Gauche では car と cdr に相当する Scm_Car と Scm_Cdr 関数が用意されています。
数値のみを含む単純なリストの値を表示する場合は、以下のようにループします。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | #include <stdio.h> #include <gauche.h> int main() {        ScmObj p;     ScmObj list;     GC_INIT();     Scm_Init(GAUCHE_SIGNATURE);     list = SCM_LIST3(SCM_MAKE_INT(1), SCM_MAKE_INT(2), SCM_MAKE_INT(3));     for(p = list; SCM_PAIRP(p); p = Scm_Cdr(p)) {         printf("%ld\n", SCM_INT_VALUE(Scm_Car(p)));     }     return 0; } | 
for ループのところでは、list の先頭から Scm_Cdr で順番に辿っています。
ループの内側では、Scm_Car で要素を取り出し、それを表示しています。
実行すると以下の出力が得られます(※「C言語からGaucheを使おう! (1)」で作成した Makefile を使用しています)。
| 1 2 3 4 | > make run 1 2 3 | 
同様の処理を行う SCM_FOR_EACH というマクロもありますので、上記コードは以下のように書きなおすことができます。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | #include <stdio.h> #include <gauche.h> int main() {        ScmObj p;     ScmObj list;     GC_INIT();     Scm_Init(GAUCHE_SIGNATURE);     list = SCM_LIST3(SCM_MAKE_INT(1), SCM_MAKE_INT(2), SCM_MAKE_INT(3));     SCM_FOR_EACH(p, list) {         printf("%ld\n", SCM_INT_VALUE(Scm_Car(p)));     }     return 0; } | 
その他のリスト操作
他にもリストを操作する多くの関数はが提供されています。
Scheme で定義されているリスト操作用の手続きに対応する C 言語関数が存在します。
いくつか試してみましょう。
| 1 2 3 4 5 6 7 8 | /* リストの長さを取得する */ Scm_Length(list); /* (length list) */ /* 要素を反転したリストを生成する */ Scm_Reverse(list); /* (reverse list) */ /* 複数のリストを結合したリストを生成する */ Scm_Append(SCM_LIST(list1, list2)); /* (append list1 list2) */ | 
まとめ
前回は値の生成、今回はリスト操作について調べました。
次回は文字列として用意した Scheme コードを eval する方法を調べようと思います。

 
						