Kahua
- 本家
- KahuaSeminar (臨時)
- 実験室
News
- ド素人とKahua (2007-07-04 13:58:34(+0900))
- Kahua Wish List (2006-09-28 06:48:12(+0900))
- Kahua Bug (2006-11-22 07:51:39(+0900))
- 日誌 (2007-07-04 14:00:20(+0900))
- Enjoy Gauche (2007-07-04 13:59:46(+0900))
Site Info
Kahua開発日記
Enjoy Gauche
2. 名前を付ける
2.1. 算数の問題
ちょっとした算数の問題を考えてみましょう.
兄の太郎くんの大きなマグカップは,内法で,直径が10cm 高さが10cmの円筒形です. 一郎くんのマグカップの容量は何cc でしょう.円周率を3.14としましょう.
円筒の体積の公式は,
体積 = 底面積×高さ
底面積 = 半径×半径×円周率
半径 = 直径/2
ですからまず,半径を求めましょう.
gosh> (/ 10 2) 5
次に,底面積を求めましょう.
gosh> (* 5 5 3.14) 78.5
最後に容量です.
gosh> (* 78.5 10) 785.0
うわっ.でかい! ワイン一本がはいっていましますねぇ.
2.1.1. 値に名前をつける
さて,円周率や直径,高さの値を数字でいちいち覚えるのは面倒ですよね. 名前が付けられると覚えやすいですね.Scheme では,define をつかって 値に名前を付けることができます.たとえば,円周率 3.14 に pi という 名前をつけましょう.
gosh> (define pi 3.14) pi
pi という名前のついた値を知りたければ,単に pi と書けばよいのです.
gosh> pi 3.14
直径と,高さにも名前をつけておきましょう.
gosh> (define d 10) d gosh> d 10 gosh> (define h 10) h gosh> h 10
2.1.2. 式に名前をつける
半径は,r にしましょう.Scheme では式にも名前がつけられます.
gosh> (define r (/ d 2)) r gosh> r 5
これは式に名前をつけてはいますが,実際にはその式を計算(評価)して 得られた「値」に名前をつけているのと同じです.
こうして名前をつけておくと,底面積は,名前 r と pi を使ってあらわせますね. そして,その底面積も a とい名前を付けておきましょう.
gosh> (define a (* r r pi)) a gosh> a 78.5
最後に容積にも taro-mag という名前を付けましょう.
gosh> (define taro-mag (* a h)) taro-mag gosh> taro-mag 785.0
2.2. 関数
さて,太郎くんの大きなマグカップの容量はわかりましたね. 何 cc ですか?また,計算しなくていもいいですよね.taro-mag という名前を 付けましたから,taro-mag を評価してみればいいですね.
gosh> taro-mag 785.0
さて,太郎くんには,花子ちゃんという妹がいて,やっぱり大きなマグカップを もっています.でも,太郎くんのよりは小さいようです.
花子ちゃんのマグカップは,内法で,直径が8cm 高さが9cmの円筒形です. 花子ちゃんのマグカップの容量は何cc でしょう.円周率を3.14としましょう.
2.2.1 関数の定義
さきほどのような方法で,花子ちゃんのマグカップの容量を計算して,それに hanako-mag という名前をつけてもいいですが...きっと,次は,花子の弟が でてきそうですね.
そこで,すこし整理しましょう.「円周率」は太郎くんのときと同じです. 「直径」の方はというとこれは太郎くんのとは変化しています.また, 「高さ」も変化していますね.
「直径」の変化は何に影響しているでしょう.そうです.「半径」ですね. つまり,「半径」は直径によってその長さがかわります.そこで,「直径」から 「半径」を求める関数というものを考えます.「直径」をもらうと,それに 対応する「半径」返す仕組みです.どうすればいいでしょう.「直径」d が与えられたら,それを半分にした値を返す関数ですね.これは
(lambda (d) (/ d 2))
と書きます.これをλ(ラムダ)式といいます. このλ式をすこし説明しましょう.lambda のとなりにあるリスト (d) は 仮引数リスト「仮」というのは,関数内部で,参照する引数の「名前」である ことを意味します.(対応する言葉に「実引数」という言葉がありますが, これは,実際に関数を使うときに関数の外から与える実際の「値」のことです.) ここでは,仮引数が d のひとつだけであることがわかります. これが外から与えるデータです.仮引数リストのあとにあるのが,このλ式の 本体部分です.
実際に使うときには,(関数 引数)と書きます. たとえば,直径15(cm)のものの半径を求めてみましょう.
gosh> ((lambda (d) (/ d 2)) 15) 7.5
この場合,15 が実引数です.このとき,どのような計算が行われるかというと, 仮引数 d が実引数 15 に束縛されます.つまり,d = 15 になります. こうしておいて,本体部分 (/ d 2) が計算され,それが結果として返ります.
2.2.2. 関数に名前を付ける
いちいち,(lambda (d) (/ d 2)) と書くのは面倒なので,この式に簡単で 覚えやすい名前を付けましょう.たとえば,d2r としましょう.
gosh> (define d2r (lambda (d) (/ d 2))) d2r
さて,もうひとつ,半径から円形の底面積を求める関数はどうなるでしょう. 名前は circle-area とでもしておきましょう.
gosh> (define circle-area (lambda (r) (* r r pi))) circle-area
で,いいでしょう. 最初にもどって,底面の直径と,高さが与えられたら,マグカップの容量を計算 するという関数は,以下のように書きます.
(lambda (d h)
(let* ((r (d2r d))
(a (circle-area r))
(v (* a h)))
v))
となります.あれっ.見なれない,let* なんてのが出てきましたね.let* は 関数や define の定義の中だけで有効な名前を付けるための特別な構文です.
(r (d2r d))
(a (circle-area r))
(v (* a h))
の部分はトップレベルで
(define r (d2r d)) (define a (circle-area r)) (define v (* a h))
と書くのに対応しています.let*構文は一般的には,
(let* ((v1 expr1)
(v2 expr2)
...
)
body)
という形式になっており,expr1 の値に v1 という名前を,expr2 の値に v2 という名前を...つけた上で,body を計算した結果がこの let* 式の値に なります.
さて,底面の直径と高さから,マグカップの容積を求める関数に mag-cup という 名前を付けておきましょう.
(define mag-cup
(lambda (d h)
(let* ((r (d2r d))
(a (circle-area r))
(v (* a h)))
v)))
2.2.3. 関数の使い方
さて,これで,mag-cup という名前の関数ができました.どうやって使うのでしょう. これを使って,花子ちゃんのマグカップの容量を計算してみましょう.
gosh> (mag-cup 8 9) 452.16
おっ.結構はいりますねぇ.
このように,関数を使うときは,関数名 引数 ... と並べて括弧でかこみます. これは,前回でてきた四則演算子や string-append などの関数の使い方と同じです.
2.3. 関数定義のもうひとつの書法
Scheme では,
(define mag-cup
(lambda (d h)
(let* ((r (d2r d))
(a (circle-area r))
(v (* a h)))
v)))
と書くかわりに,
(define (mag-cup d h)
(let* ((r (d2r d))
(a (circle-area r))
(v (* a h)))
v))
のように省略して書くことができます.
2.4 練習問題
- 問題 2.1.
次の図形の表面積や体積の公式を関数で表現しなさい.
- 球の表面積 (引数:半径)
- 球の体積 (引数:半径)
- 円柱の表面積 (引数:底辺の半径,高さ)
2.5 ちょっと小難しい用語
- 関数抽象(λ抽象)
共通の計算手順を、入力から出力への変換として抽象化して表現すること。
- 関数適用(Function Application)
関数に実際の入力データを与えて、出力を計算させること。