Scheme の練習。x の n 乗を計算する power。
Scheme の練習として、x
の n
乗を計算する power
を書いてみた。
あ、そうだ。一応言っときますけど、たいていの Scheme 処理系には、expt
という手続きが用意されているはずなので、ここで示す power
なんて手続きを用意する必要はないです。以下はあくまで練習のために書いたという話です。
で、これが書いてみたやつ:
(define (power x n) (if (= n 1) x (* x (power x (- n 1)))))
ただし、n
には 1
か、1
より大きい整数を渡す事。じゃないと停止しない。
何も起こらない
これをコマンドラインから呼び出せるようにしたい。そこで、上記の内容を power
という名前のファイルに書いて、実行許可フラグを立てたり、shebang 書いたり。
%cat power #! /usr/local/bin/gosh (define (power x n) (if (= n 1) x (* x (power x (- n 1))))) %chmod +x power %./power 2 3 %
何も起こらない。main
という手続きが無いからだ。
main 手続きを書く
Gauche ユーザリファレンスの『3.3 Schemeスクリプトを書く』によると:
ファイルが正常にロードされたら、goshは userモジュールに `main' という手続きが定義されているかどうか調べ、定義されていればそれを呼びます。mainには、スクリプトへの引数のリストが唯一の引数として渡されます。リストの最初の要素はスクリプトファイル名です。
と書いてある。こういうことだな:
そこで、main
手続きを何とか書いてみた。
#! /usr/local/bin/gosh (define (power x n) (if (= n 1) x (* x (power x (- n 1))))) (define (main args) (display (power (string->number (car (cdr args))) (string->number (car (cdr (cdr args)))))) (display "\n"))
power を、2 つの引数を与えて呼び出したいだけなのに、なんだかすごいことになってる。
でも、とりあえず動きます。
%./power 2 3 8 %
cadr caddr
すごい事になっちゃってる car
と cdr
の嵐をなんとかする:
(define (main args) (display (power (string->number (cadr args)) (string->number (caddr args)))) (display "\n"))
少しは読みやすくなったかな。
(car (cdr x))
は (cadr x)
と書ける。(car (cdr (cdr x)))
は (caddr x)
と書いても同じこと。
first second third
リスト操作ライブラリの SRFI-1
を使って、もうちょっと:
#! /usr/local/bin/gosh (use srfi-1) (define (power x n) (if (= n 1) x (* x (power x (- n 1))))) (define (main args) (display (power (string->number (second args)) (string->number (third args)))) (display "\n"))
(use srfi-1)
とすることによって、ライブラリを読み込んだので、second
とか third
が使えるようになった。
ちなみに、この場合 (first args)
は、スクリプトの名前を返します。
2 の 100 乗。
%./power 2 100 1267650600228229401496703205376 %echo '2^100' | bc 1267650600228229401496703205376
あってる。
参考文献
- Gauche ユーザリファレンス
- http://practical-scheme.net/gauche/man/gauche-refj.html
- Manpage of bc
- http://www.linux.or.jp/JM/html/GNU_bc/man1/bc.1.html
- carはカー、cdrはクダー、ではcadrやcaddrは? - *「ふっかつのじゅもんがちがいます。」withぬこ
- http://d.hatena.ne.jp/ajiyoshi/20080902/1220350887