第 5 章 条件分岐

ようやく条件分岐まで来た。サボりまくってたので時間が掛かった。

5.2

条件分岐の構文

if 条件 then 式(真)else 式(偽)

C なんかの書き方とほとんど一緒。
注意。

  • 結果の2つの式は同じ型でなくてはならない
  • else は省略出来ない

トップレベル曰く、else を省略すると偽の場合の式が unit 型として評価される。

# let x = 3;;
val x : int = 3
# if x > 5 then true;;
Characters 14-18:
  if x > 5 then true;;
                ^^^^
Error: This expression has type bool but is here used with type unit
# if x > 5 then true else false;;
- : bool = false

問題 5.1 の (4) でビックリした。 OCaml って真偽値の大小比較が出来るのか!
大小関係はこうなってる。

true > false (* true のほうが大きい *)

真偽値の大小比較ってどんな場合に便利なんだろう。ちょっと思いつかないな。
今まで真偽値の大小比較が出来る言語って触ったことがない人は知らないとカルチャーショックを受ける言語仕様。
参考リンク
真偽値の大小比較:Rainy Day Codings:So-net blog
問題 5.1 の (5) もちょっとややこしいな。
条件分岐のあとに返ってくる値は評価されたあとの物が返ってくるみたい。

# if not(3 = 4) then 1 < 2 else 1 > 2;;
- : bool = true
5.4

if 文を他の式中に埋め込んで使う書き方。
本の例だと、まず普通?に書いた場合は

let kyuyo x = if x < 30 then kihonkyu + x * jikyu
                        else kihonkyu + x + yugu_jikyu

埋め込んで書いた場合は

let kyuyo x =
  kihonkyu + x * (if x < 30 then jikyu else yugu_jikyu)
5.5

条件分岐に対するデザインレシピの話。
関数定義のデザインレシピを拡張して考える。

  • 条件の場合分けを考える
  • 各場合について 1 つ 1 つテストする


新しい単項演算子が出てきた。プラスマイナスを反転させる演算子

0.0 -. x = -. x

という動作になっているみたい。


サポートページに問題 5.2 の解答例がないみたいなので貼っておく。

(* 目的:時間(24時間表示)を受け取って午前か午後かを判定する関数 *)
(* jikan : int -> string *)
let jikan time = if time > 12 then "pm"
                       else "am"
					   
(* test case *)
let test1 = jikan 5 = "am"
let test2 = jikan 16 = "pm"
let test3 = jikan 12 = "am"
let test4 = jikan 13 = "pm"

問題 5.3 もやったので一応載せてみる。

(* 目的: 誕生月 month と誕生日 day を受け取ったら 12 星座を返す関数 *)
(* seiza : int -> int -> string *)
let seiza month day =
    if month = 1 then if  1 <= day && day <= 19 then "Cap"
	         else if 20 <= day && day <= 31 then "Aqr"
                 else "none"
    else if month =  2 then if  1 <= day && day <= 18 then "Agr"
	               else if 19 <= day && day <= 29 then "Psc"
                       else "none"
    else if month =  3 then if  1 <= day && day <= 20 then "Psc"
	               else if 21 <= day && day <= 31 then "Ari"
                       else "none"
    else if month =  4 then if  1 <= day && day <= 19 then "Ari"
	               else if 20 <= day && day <= 30 then "Tau"
                       else "none"
    else if month =  5 then if  1 <= day && day <= 20 then "Tau"
	               else if 21 <= day && day <= 31 then "Gem"
                       else "none"
    else if month =  6 then if  1 <= day && day <= 22 then "Gem"
	               else if 23 <= day && day <= 30 then "Cnc"
                       else "none"
    else if month =  7 then if  1 <= day && day <= 22 then "Cnc"
	               else if 23 <= day && day <= 31 then "Leo"
                       else "none"
    else if month =  8 then if  1 <= day && day <= 22 then "Leo"
	               else if 23 <= day && day <= 31 then "Vir"
                       else "none"
    else if month =  9 then if  1 <= day && day <= 22 then "Vir"
	               else if 23 <= day && day <= 30 then "Lib"
                       else "none"
    else if month = 10 then if  1 <= day && day <= 23 then "Lib"
	               else if 24 <= day && day <= 31 then "Sco"
                       else "none"
    else if month = 11 then if  1 <= day && day <= 22 then "Sco"
	               else if 23 <= day && day <= 30 then "Sgr"
                       else "none"
    else if month = 12 then if  1 <= day && day <= 21 then "Sgr"
	               else if 22 <= day && day <= 31 then "Cap"
                       else "none"
    else "none"
	
(* test case *)
let test1 = seiza  8 17 = "Leo"
let test2 = seiza  3 20 = "Psc"
let test3 = seiza  6  1 = "Gem"
let test4 = seiza  2 28 = "Psc"
let test5 = seiza 11 25 = "Sgr"
let test6 = seiza 11 22 = "Sco"

何だか冗長な感じになっちゃったな。でも解答例もこんな感じだし、このままでいいか。

5.6

複雑な条件判定は if 文をネストすることで表現出来る。この辺は手続き型と一緒かな。
条件が複雑になって可読性が落ちそうなら、補助関数を作って見通しを良くする方法がある。
問題 5.4 から 5.7 は特に難しい部分はなかった。

5.7

条件分岐でも左結合で評価される。