HOME | 3. リストを作ろう | もうひとつの Scheme 入門 | 5. 分岐 | 書き込む |
関数の定義をするようになると処理系のコマンドラインからコードを打ち込むのは不便ですので、エディタで コードを編集してから、処理系にロードさせることになります。
ここでは、第一章でセットアップした Emacs での作業を例にとって話を進めます。DrScheme を用いた場合も 基本的にはほとんど同じです。 Emacs を立ち上げて、 (C-x 2) または メニューの File → Split Window で Emacs のウィンドウを上下に分割します。 その後、(C-x C-f) または File → Visit New File で新しいファイルを作成します。 作成するディレクトリはたとえば "C:\doc\scheme" とし、ファイル名は "hello.scm" とします。 新しいファイルに、[code 1] のコードを打ち込んでみてください。
[code 1] (hello.scm)
; Hello world as a variable (define vhello "Hello world") ;1 ; Hello world as a function (define fhello (lambda () ;2 "Hello world"))入力が終わったら (C-x C-s) または、File → Save で保存します。
次に (C-c C-l) または、メニュー の Scheme → Load Scheme File を用いて ファイルを処理系のロードします。 さて、プログラムのロードがすんだら (C-x o) で下側のウィンドウに飛び、 '> ' の後に次のように入力してください。入力が済むと 図 1 のような画面になると思います。
このように、 エディタを用いたコードの編集と、 処理系でのテストを繰り返すことによって、 Scheme プログラムを作成していきます。こまめにテストすることによって、 プログラムの信頼性が高まり、作業効率もよくなります。 エディタによっては ソースコードを部分的に評価する機能を備えたものもあり、ロードする手間が省けることがあります。 (Emacs の場合はA-6: Emacs の使いかたを参照してください。)
> vhello "Hello world" > fhello #<procedure:fhello> > (fhello) "Hello world"
define はグローバル変数を宣言する命令で、 2つの引数をとります。この命令は、最初の引数の名前の変数を宣言すると同時にその値を2番目の引数の値にします。 つまり、[code 1] の ;1 の部分は、vhello という変数を宣言し、 その値を "Hello world" にするということを意味します。
それに対し、[code 1] の ;2 の部分は、"Hello world" を返す手続き fhello
を宣言しています。
手続きを定義するには lambda という特殊形式を使います。lambda
は1つ以上の引数をとり、最初の引数は
定義する手続きがとる引数のリストです。この場合は引数を取らないので引数のリストは () になります。
処理系に vhello と入力するとその値 "Hello world" が返ってきます。
fhello と入力しても同様にその値 #<procedure:fhello> が返ってきます。
これは、Scheme が手続きを他のデータと同じように扱っていることを意味します。
前回説明したように、
Scheme は全てのデータをそのメモリー上のアドレスで管理しているので、メモリーにあるものは何でも一元管理できます。
fhello を手続きとして呼び出すためには (fhello) というように括弧でくくります。そうすると、
前々回で説明した手順を
踏んでこの式が評価され、その値 "Hello world" が返ってきます。
[code 2] (farg.scm)
; hello with name (define hello (lambda (name) (string-append "Hello " name "!"))) ; sum of three numbers (define sum3 (lambda (a b c) (+ a b c)))保存したら、scheme 処理系にロードして、関数を呼び出してみてください。
> (hello "Lucy") "Hello Lucy!" > (sum3 10 20 30) 60
以下の例は、関数に渡った引数をリストにして返す関数です。 3 つの通常の引数とレストパラメータをとります。 通常の引数の後に、ドットで区切って、レストパラメータを書きます。
(define three-args+ (lambda (a b c . d) (list a b c d)))
以下は実行例です。 レストパラメータがリストとして 関数本体に渡っているのがわかると思います。
> (three-args+ 2 3 4) (2 3 4 ()) > (three-args+ 2 3 4 5) (2 3 4 (5)) > (three-args+ 2 3 4 5 6 7) (2 3 4 (5 6 7))
[code 3]
; hello with name (define (hello name) (string-append "Hello " name "!")) ; sum of three numbers (define (sum3 a b c) (+ a b c)) ; returning a list of three and additional arguments (define (three-args+ a b c . d) (list a b c d))[code 3] に示すように、呼び出されるときの形で関数を定義します。 [code 3] は [code 2] と全く同等です。この記法を嫌う人もいますが、 コードが短くなることに越したことは無いので、この解説では遠慮なく使います。
関数定義は define を使って行います。 関数を定義するときは、処理系に直接打ち込むよりも、エディタを使ってソースコードを作ってから それをロードする方が能率的です。Emacs を使うと便利よく編集とテストができます。
次回は分岐について述べます。 分岐ができるようになると、それなりのプログラムが書けます。
; 1 (define (inc x) (+ x 1)) ; 2 (define (dec x) (- x 1))
; definition of pi (define pi (* 4 (atan 1.0))) ; degree -> radian (define (radian deg) (* deg (/ pi 180.0))) ; free fall time (define (ff-time vy) (/ (* 2.0 vy) 9.8)) ; horizontal distance (define (dx vx t) (* vx t)) ; distance (define (distance v ang) (dx (* v (cos (radian ang))) ; vx (ff-time (* v (sin (radian ang)))))) ; t処理系にロードした後、以下のように入力するとボールが飛ぶ距離 (m) が計算されます。
> (distance 40 30)
141.39190265868385
141.4 m と計算されます。空気抵抗を考慮に入れていないので若干大きめですが、
妥当な値が出てきました。
HOME | 3. リストを作ろう | もうひとつの Scheme 入門 | 5. 分岐 | 書き込む |