「プログラミングの基礎」読みほぐし⑤
今回は 4.6 関数定義に対するデザインレシピについて見ていきます。
難しい内容(少なくともぼくにとっては)のため、今回はこの節のみ見ていきます。
では始めましょう。
関数定義に対するデザインレシピ
デザインレシピとはなんでしょうか。ぼくはこの言葉を初めて聞きました。
デザインレシピとは、プログラム作成時に従うべき指針となるもののことのようです。
関数定義に対するデザインレシピは下記です。
目的
- 作成する関数が何をするものかを考えます
- 何を受け取り、何を返すのかを考え、関数の型を決定します
- これをもとに関数の出だしを作成します
例
- 関数の動きを具体的にします
- そのためには、関数に望まれる入力と出力の例を作成します
- それを実行可能なプログラムにします
本体
- 関数の本体を作成します
- 目的の段階では関数が「何を」するのか考えましたが、ここではそれを「どうやって」実現するかを考えます
テスト
- 望む動作をしているか確認します
- 例で作ったテストプログラムを使って確認します
- 望む動作をしていなかったら、このデザインレシピに沿って原因を考え、誤りがあれば修正します
準備
関数を作り始める前に、kyuyo.ml というファイルを用意します。
そうです、今回から外部ファイルを使ってプログラムを書いていくのです。
ファイルが用意できたら、適当なエディタで kyuyo.ml を開きます。
デザインレシピをに従って関数を作るときには、必ずファイルを開いてそこに関数を作ります。そして、実行するときにはそのファイルを読み込むようにします。
こうしておくと、プログラムに間違いがあったときなどにも簡単に訂正して読み込み直すことができます。
やってみる
関数のヘッダを作る
最初に考えることは、作成する関数の目的です。
これから作ろうとしている関数は「働いた時間に応じたアルバイト代を計算すること」とします。
まず関数について、下記のようなルールを定めます。
- 関数名は kyuyo とする
- 働いた時間もアルバイト代も整数を使う(よって、関数の型は int -> int となる)
- 働いた時間を x という変数で表す
これらの情報はヘッダにまとめます。
次のように書きます。
(* 目的: 働いた時間 x に応じたアルバイト代を計算する *) (* kyuyo: int -> int *) let kyuyo x = 0
このカッコ内 (* 米 *)
はコメントです。
また、OCaml インタプリタに直接プログラムを書いていたときは ;;
が必要でしたが、ファイルに関数を書く場合は不要です。
さて、これで関数のヘッダができました。
例(テスト)を作る
OCaml インタプリタで #kyuyo 25 ;;
などといちいちテストを実行して行くのでは面倒です。
なので、これらを実行可能なテストプラグラムとしてまとめて書きます。具体的には以下のように書きます。
(* テスト *) let test1 = kyuyo 25 = 23850 let test2 = kyuyo 28 = 26700 let test3 = kyuyo 31 = 29550
ここで1 行目はカッコを使うと let test1 = (kyuyo25 = 23850)
となります。
まぎらわしいですが、まず最初の =
は変数 test1
を定義するもので、二つ目の =
は値が正しいかどうか確かめるための演算子となっています。
関数が正しく動作している場合は、これらのテストはすべて true
となります。
実行(1)
kyuyo.ml を保存し、OCaml インタプリタから読み込んでみましょう。
読み込みには、次のように #use
という命令を使用します。
// kyuyo.ml の存在するディレクトリに移動する # #use "kyuyo.ml" ;; // 実行結果 val kyuyo : 'a -> int = <fun> val test1 : bool = false val test2 : bool = false val test3 : bool = false
テスト結果がすべて false
となってしまいました。
これは、まだ本体を作っておらず、いつも 0
を返すようにしているからです。
ちなみに、先に関数の本体として型の合う適当な値を入れたのは、ここでテストを実行できるようにするためです。
さて、この先は目標ができます。
テストの結果をすべて true
にすれば良いのです。
テストはプログラムの正当性を完全に保証するものではありませんが、テストを行っていないプログラムよりは信頼性は格段に高くなります。ですから入出力の例を作ったら必ずそれをテストプログラムとして書いておきましょう。
関数を完成させる
それでは関数を完成させ、プログラムを完成させましょう。
最終的なプログラム( kyuyo.ml) の内容は下記です。
// ヘッダここから // プログラムの中身を見なくてもこのヘッダを見れば、何をするプログラムかわかります。 (* 目的: 働いた時間 x に応じたアルバイト代を計算する *) (* kyuyo: int -> int *) // 本体ここから (* 時給(円)*) let jikyu = 950 (* 基本給(円)*) let kihonkyu = 100 (* 計算 *) let kyuyo x = kihonkyu + x * jikyu // テストここから (* テスト*) let test1 = kyuyo 25 = 23850 let test2 = kyuyo 28 = 26700 let test3 = kyuyo 31 = 29550
実行(2)
プログラムが出来上がったらいよいよテストです。
# #use "kyuyo.ml" ;; val jikyu : int = 950 val kihonkyu : int = 100 val kyuyo : int -> int = <fun> val test1 : bool = true val test2 : bool = true val test3 : bool = true
まとめ
以上がデザインレシピを使ったプログラムの書き方となります。
この考え方は、作っているプログラムの種類やプログラミング言語にかかわらず使用することができます。
これで第4章は終了です。 次回は第5章 条件分岐 に進みます。