Schemeでは計算というのは式の値を求めることです。
Schemeの式は以下のとおりに表現されているものです。
- ひとつの塊(シンボルおよびリテラル)として表現されるもの。
この構文のことをアトムということがあります
- 複数の式を括弧((と))で囲って表現されるもの。
この構文のことをリストということがあります
- 1. により、map、string=?、*、-5、3.14、
"The Wizard Book"、#\a はどれも式です。
- 2. により、(- 1 (* 2 3))、
(string->list (string-map char-upcase "wikiwiki"))
も式です。
式が表す値に名前をつけることを定義といいます。Schemeでは式が表す値に
名前を付けることによって、複雑な構成の式をひとつのものとして抽象化して
表現することができます。
すべて式とはどういうことか
たとえば、Schemeではifは制御構造ではありません。
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
と計算できます。
代入(assignment)がなくても計算はできる
Schemeにおいて計算する対象がすべて式であるなら、代入文(assignment statement)はないということ
になります。なぜなら、すべて式なのであれば、代入を使わなくても置き換え(substitution)モデルで説明可能だからです。
代入文がなくてプログラムが書けるかを確かめてみましょう。
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)))
欲しいものが「何か」を書いただけです。
でも欲しいものはちゃんと書けているということが分ります。
どこにも代入は必要ありませんでした。
ではなぜ、最初は代入が必要だと思ったのでしょう。
「プログラムは計算の手順を書いたもの」という先入観がどこかに
ありませんでしたか。
ここでは整数和の例で確かめてみましたが、
一般的にそれ以外の計算でも多くの場合,代入を使わないで分りやすく
プログラミングすることができます。
とはいうものの,代入を使うのが本質的だと思われている処理を簡単に扱うために
Schemeではちゃんと代入を行う手続きが使えるようになっています.
(山下 伸夫)