今まで、Scheme のスクリプトは頭から順に実行されるもんだと思っていたけど、そうでもないらしい。main という名前の関数(Scheme では手続きというのか)が定義されていると、それがスクリプトのエントリポイントになる。
cf. 3.3 Schemeスクリプトを書く – Gauche ユーザリファレンス
ファイルが正常にロードされたら、goshは userモジュールに ‘main’ という手続きが定義されているかどうか調べ、 定義されていればそれを呼びます。mainには、スクリプトへの引数のリストが 唯一の引数として渡されます。リストの最初の要素はスクリプトファイル名です。
試してみよう。
(define main (lambda (args) (print args)))
実行:
^o^ > gosh main.scm foo bar baz (main.scm foo bar baz)
確かに main 手続きが実行された。
じゃあ、昨日の nend.scm を main 手続きを使って、引数をコマンドラインから渡せるように変更してみよう。
(define divmod (lambda (n m) (list (div n m) (modulo n m)))) (define mul (lambda (n) (let loop ((dm (divmod n 10)) (l '())) (if (= (car dm) 0) (apply * (cons (cadr dm) l)) (loop (divmod (car dm) 10) (cons (cadr dm) l)))))) (define nend (lambda (n) (let loop ((x n) (i 0)) (if (< x 10) i (loop (mul x) (+ i 1)))))) (define nend_smallest (lambda (n) (let loop ((i 1)) (if (= (nend i) n) i (loop (+ i 1)))))) (define main (lambda (args) (print (nend_smallest (string->number (cadr args))))))
^o^ > gosh nend2.scm 2 25 ^o^ > gosh nend2.scm 3 39 ^o^ > gosh nend2.scm 4 77 ^o^ > gosh nend2.scm 5 679
うまくいった。
ところで、今まで書いてきたみたいに手続きの外に (print ...)
があるとどうなるんだろう。
(print "Hello, world.") (define main (lambda (args) (print args)))
実行してみると:
^o^ > gosh main2.scm foo bar baz Hello, world. (main2.scm foo bar baz)
(print "Hello, world.")
と main 手続きが両方実行されたよ。