今まで、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 手続きが両方実行されたよ。