こんにちは、鈴木です。
「C言語からGaucheを使おう!」シリーズです。
前回の「C言語からGaucheを使おう! (5) Scm_Evalでevalする」では eval する方法を調べました。
今回は Scheme の apply 手続き相当の処理を行う方法を調べます。
Scm_Apply 関数
以下の Scheme プログラムに相当する処理を行ないたいと思います。
1 2 |
(define square (lambda (x) (* x x))) (apply square '(10)) |
サンプルコードです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
#include <stdio.h> #include <gauche.h> int main() { ScmObj procedure; ScmEvalPacket eval_packet; GC_INIT(); Scm_Init(GAUCHE_SIGNATURE); /* (1) 値を 2 乗する手続き square を定義. */ Scm_EvalCString("(define square (lambda (x) (* x x)))", SCM_OBJ(Scm_UserModule()), &eval_packet); /* (2) 定義した square を取得. */ procedure = Scm_GlobalVariableRef(Scm_UserModule(), SCM_SYMBOL(SCM_INTERN("square")), SCM_BINDING_STAY_IN_MODULE); /* (3) (apply square '(10)) */ if(Scm_Apply(procedure, SCM_LIST1(SCM_MAKE_INT(10)), &eval_packet) < 0) { printf("[%s] %s\n", SCM_STRING_CONST_CSTRING(Scm_ConditionTypeName(eval_packet.exception)), SCM_STRING_CONST_CSTRING(Scm_ConditionMessage(eval_packet.exception))); } else { /* (4) 結果を表示. */ printf("%ld\n", SCM_INT_VALUE(eval_packet.results[0])); } return 0; } |
処理ごとにコメントを付けました。
(1) では、前回までに登場した Scm_EvalCString を用いて、値を 2 乗する square という手続きを定義しています。
(2) は初めての関数 Scm_GlobalVariableRef が登場しました。この関数は、名前からしてグローバル変数の参照を取得するもののようです。
(3) では Scm_Apply 関数を用いて「(apply square '(10))」相当の処理を行なっています。エラーハンドリングは Scm_Eval などと同様です。
(4) では結果を取得して、表示しています。
それでは実行してみましょう。(※「C言語からGaucheを使おう! (1) コンパイル環境を整える」で作成した Makefile を使用します)
1 2 |
> make run 100 |
期待通り「100」という結果が得られました。
まとめ
今回のポイントは、Scm_Apply の第一引数にはシンボルではなく Scm_GlobalVariableRef で取得した参照を渡す点でしょうか。
次回はいよいよ、Scheme プログラムを load する方法を調べようと思います。
Comments
squareに渡している引数が10じゃなくて3になっています。
ありがとうございます!
間違っていた箇所を修正しました。