これまでの分析により、関数定義の骨組みが定まりました。まず、小石の総数を表すtotalという変数が必要になります。これが関数から返される値となります。
次に、この関数には引数が必要であることが分かります。この引数は、三角形の行数の合計となります。number-of-rows と呼ぶことができます。
最後に、カウンタとして使用する変数が必要です。この変数をcounterと呼ぶこともできますが、row-numberとする方が適切です。というのも、この関数におけるカウンタの役割は行数を数えることであり、プログラムは可能な限り分かりやすく記述すべきだからです。
Lispインタプリタが関数内の式の評価を最初に開始する際、total
には何も加算されていないため、その値は0に設定されるべきです。その後、関数は1行目の小石の数を合計に加算し、次に2行目の小石の数を合計に加算し、さらに3行目の小石の数を合計に加算するというように、加算すべき行がなくなるまでこれを繰り返します。
total と row-number
はいずれも関数内でのみ使用されるため、let
でローカル変数として宣言し、初期値を設定できます。明らかに、total の初期値は 0
であるべきです。row-number の初期値は、最初の行から開始するため、1
であるべきです。つまり、let の文は次のようになります。
(let ((total 0)
(row-number 1))
body...)
内部変数を宣言し、初期値にバインドした後、while ループを開始できます。判定式は、row-number が number-of-rows
以下である限り、真の場合に t
という値を返す必要があります。(もしこの式が、行番号が三角形の行数未満である場合にのみ真と判定されるなら、最終行が合計に加算されなくなります。したがって、行番号は行数以下である必要があります。)
Lispには、第1引数の値が第2引数の値以下であればtrueを、そうでなければfalseを返す<=関数が用意されています。したがって、whileがテストとして評価する式は、次のようになるはずです。
(<= row-number number-of-rows)
小石の総数は、ある行にある小石の数を、すでに求めた合計に繰り返し加算することで求めることができます。その行にある小石の数は行番号に等しいため、行番号を合計に加算することで総数を求めることができます。(明らかに、より複雑な状況では、その行にある小石の数が行番号とより複雑な関係にあるかもしれません。その場合、行番号は適切な式に置き換えられることになります。)
(setq total (+ total row-number))
これにより、total の新しい値が、行内の小石の数を前回の合計に加えた値と等しくなります。
totalの値を設定した後、ループの次回の繰り返しがある場合は、そのための条件を整える必要があります。これは、カウンタとして機能するrow-number変数の値をインクリメントすることで行われます。row-number変数をインクリメントした後、whileループの冒頭にある真偽判定により、その値が依然としてnumber-of-rowsの値以下であるかどうかが判定され、そうであれば、row-number変数の新しい値がループの前回の繰り返しにおけるtotalに加算されます。
Emacs Lispの組み込み関数 1+ は数値に1を加算するため、変数 row-number はこの式でインクリメントできます:
(setq row-number (1+ row-number))