プログラミング in OCaml 3rd chapter 練習問題を解いた

練習問題 3.1

1-3は解いたけどソース消えたので気が向いたらやる, 4は `String.capitalize_ascii` を使う邪道プレイした

練習問題 3.2

b1 && b2 を if式と true, false, b1, b2のみを用いて同じ意味になるように書き直しなさい。式 b1 || b2も同様に書き直しなさい。

という問題。trueもfalseもいらんな?と思いながら脳死で書いた

let and' b1 b2 = if b1 then b2 else b1;;
let or' b1 b2 = if b1 then b1 else b2;;

練習問題 3.3

ドモルガンの法則でやってあげるだけ

let and'' b1 b2 = not (not b1 || not b2);;
let or'' b1 b2 = not (not b1 && not b2);;

練習問題 3.4, 3.5

省略

練習問題 3.6

1

この問題sqrt使っていいのか・・・?

let geo_mean x y = sqrt (x * y);;
2
let bmi name t w =
  let bmi_index = w /. (t *. t) in
  let cond =
    if bmi_index < 18.5 then "やせ"
    else if bmi_index < 25.0 then "標準"
    else if bmi_index < 30.0 then "肥満"
    else "高度肥満" in
      name ^ "さんのBMIは" ^ cond ^ "です";;
3
let sum_and_diff (x, y) = (x + y, x - y);;
(* f( sum_and_diff (x, y)) = (x, y) になるようなf *)
let f (p, q) = ((p + q) / 2, (p - q) / 2);;

練習問題3.7

1
let pow x n =
  let rec calc (i, p) = if i = n then p else calc (i+1, p * x)
  in calc (0, 1);;

2

(*
  pow 1 1000000000;; 
  pow' 1 1000000000;;
  とかやったらpow'の方が早かったしいいっしょ(適当)
*)
let rec pow' x n =
  if n mod 2 = 0 then
    let c = pow' x (n / 2) in
    c * c
  else if n == 1 then x
  (* x ^ (2n + 1) = x * (x ^ 2n) = x * ((x ^ n) ^ 2) *)
  else x * pow' x (n - 1);;

練習問題 3.8

練習問題3.7.1が反復的な回答なので省略

練習問題 3.9

(* fact 4
  = cond ((4 = 1), 1 , 4 * fact (4 - 1))
  = cond (false, 1, 4 * fact(3))
  = cond (false, 1, 4 * (cond (false, 1, 3 * fact(2))))
  = cond (false, 1, 4 * (cond (false, 1, 3 * (cond ((2 = 1), 1, 2 * fact(1)))))
  ...
 *)

この問題は fact 4を考えるよりも fact 1を考えたほうがわかりやすい。

(* fact 1
  = cond ((1 = 1), 1 , 1 * fact (0)) <- n を 1に置き換えただけ、
  = cond (1, 1, 1 * (cond ((0 = 1), 1, 0 * fact (0 - 1)))
  ...
 *)

という風に基底部である n = 1の時に止まらない。
これは if式が条件式によってe1とe2のどちらかのみを評価するが、OCamlの評価戦略ではe1, e2共に評価されるようになっているためである。

練習問題 3.10

省略

練習問題 3.11

1
let gcd x y =
  let rec calc x y =
    if x mod y = 0 then y
    else calc y (x mod y)
  in
    if x > y then calc y x
    else calc x y;;
2
let comb n m =
  (* n * n - 1 * .. * k を返す関数, fact_k n 1 でn!を求めることができる*)
  let rec fact_k n k =
    if n = k then k
    else n * fact_k (n - 1) k
  in
    let numerator = fact_k n (n - m + 1)
    and denominator = fact_k m 1
    in
      numerator / denominator;;
3
let iterfib n =
  let rec calc a b c =
    if c == n then a + b
    else calc b (a + b) (c + 1)
  in
    calc 0 1 1;;
4
let max_ascii s =
  let l = String.length s
  in
    let rec calc c index =
      if l == index then c
      else calc (max s.[index] c) (index + 1)
    in
      calc s.[0] 0;;

解説記事書いてる人ってすごいんだな、と思った。(小並感)