こんにちは、鈴木です。
「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 する方法を調べようと思います。