Scheme では計算というのは式の値を求めることです。
Scheme の式は以下のように表現されているものです。
- ひとつ塊(シンボルおよびリテラル)として表現されるもの(この構文のこと
をアトムということがあります)
- 複数の式を括弧((と))で囲って表現されるもの(この構文のこ
とをリストということがあります)
- 1. により、map、string=?、*、-5、3.14、
"The Wizard Book"、#\a などはどれも式です。
- 2. により、(- 1 (* 2 3))、
(string->list (string-map char-upcase "wikiwiki"))
なども式です。
式が表す値に名前をつけることを定義といいます。Schemeでは式が表す値に
名前を付けることによって、複雑な構成の式をひとつのものとして抽象化して
表現することができます。
計算機に計算をさせるには、対話型のインタプリタを使うのが簡単です。
式が表す値はその式を評価(eval)すること、すなち計算することによって
得られます。式が表す値を確認するために対話型のインタプリタを起動して計
算をさせてみましょう。
コマンドラインでgoshとタイプするとインタプリタが起動します。
$ gosh
> _
起動するとインタプリタは> という入力促進記号(プロンプト)を出力して、
ユーザからの入力待ち状態になります。ここで式をタイプして最後にリターン
キーを押すとインタプリタはユーザがタイプした式を読み(read)、
それを評価(eval)し、結果を印字(print)し、再びプロンプトを出し
て入力待ち状態になります。
gosh> 1
1
gosh> _
他にも試してみましょう。
gosh> "hello"
"hello"
gosh> (+ 1 3)
4
gosh> (let1 abs (lambda (n)
(if (<= 0 n)
n
(- n)))
(abs -1))
1
すべて式とはどういうことか
たとえば、Scheme では if は式なので値を返します。
a に「bの絶対値」を加算するプログラムを考えて見ましょう。
絶対値を求める手続き abs を使わないとすると、
(define (a-plus-abs-b a b)
(if (>= b 0)
(+ a b)
(- a b)))
と書けます。これは if 式全体の値が手続き適用したときの値として返されま
す。また、if 式は値を返すので、その値そのものとみなすことができるので、
(define (a-plus-abs-b a b)
(+ a (if (>= b 0)
b
(- b)) ))
のように b の値の正負によって,b か -b を返すように書いています。
さらに Scheme では手続きそのものも値ですので、手続きを値として返す
式を書けます。以下の定義で if 式は b が正の値なら + 手続きを、
負の値なら - 手続きを返しています。
(define (a-plus-abs-b a b)
((if (> b 0)
+
-) a b))
例えば a が 23、b が 16 ならば、
((if (> 16 0) + -) 23 16)
↓
(+ 23 16)
↓
39
aが12、bが-74ならば、
((if (> -74 0) + -) 12 -74)
↓
(- 12 -74)
↓
86
と計算できます。
代入がなくても計算はできる
Schemeにおいて計算する対象はすべて式であるなら、代入文はないということ
になります。代入文がなくてプログラムが書けるのでしょうか。
書けます。
1 から指定した上限 n までの整数の和をもとめる計算を考えてみましょう。
1 + 2 + ... + (n-1) + n
このプログラムを書くのに代入文が欲しいですか。
こんな風に計算させようとしていますか。
- s に 0 を代入
- i に 1 を代入
- i が n を超えない間 4 〜 5 を実行、n を超えたら 6 へ
- s + i を計算してその結果を s に代入
- i + 1 を計算してその結果を i に代入
- s の値を印字
なるほど。これで計算できるような気がします。でもこれで本当に欲しい
ものが手にはいるかどうかは、よくよく読んで検討しないと分りませんね。
こんな風に欲しいものを「どのように」得るかの手順を考えるのではなくてもっと、
単純に考えることもできます。これを行う関数を sum としましょう。
こんな風に考えます。
- n が 1 のとき、(sum n) の値は 1
- n が 1 より大きいとき、(sum n) の値は、ひとつ手前 (n-1) までの和
(すなわち (sum (- n 1))) と n との和
これを書くと、
(define (sum n)
(if (= n 1)
1
(+ (sum (- n 1)) n)))
欲しいものが「何か」を書いただけです。でも欲しいものはちゃんと書けてい
るということは分りますよね。どこにも代入は必要ありませんでしたね。
ではなぜ、最初は代入が必要だと思ったのでしょう。
「プログラムは計算の手順を書いたもの」という先入観がどこかに
ありませんでしたか。
|