相変わらず2日目もOCamlやってますよ。
今度は関数の定義とかの3章です。
Exercise 3,4
問題
Exercise3 2実数の相乗平均をとる関数 geo_mean を定義せよ.
Exercise4 2行2列の実数行列と2要素の実数ベクトルの積をとる関数 prodMatVec を定義せよ. 行列・ベクトルを表現する型は任意でよい.
自分の答え
open Printf (* Exercise 3 *) let geo_mean x y = sqrt (x *. y);; Printf.printf "%f\n" (geo_mean 5.0 10.0);; (* Exercise 4 *) let prodMatVec ((x1, y1), (x2, y2)) (x3, y3) = (x1*.x3+.x2*.y3, y1*.x3+.y2*.y3);; let print_vec (a1, a2) = Printf.printf "(%f, %f)\n" a1 a2;; print_vec (prodMatVec ((1.0, 2.0), (3.0, 4.0)) (5.0, 6.0));;
Exercise 7,8
問題
Exercise7 x は実数,n は 0 以上の整数として, xn を計算する関数 pow (x,n) を以下の2種類定義せよ.
1. pow の(再帰)呼出しを n 回伴う定義
2. pow の(再帰)呼出しは約 log2 n 回ですむ定義. (ヒント: x2n = (x2)n である.では,x2n+1 = ?)
Exercise8 前問の pow の最初の定義を反復的にした powi を定義せよ. (もちろん引数の数は一つ増える.呼出し方も説明せよ.)
自分の答え
open Printf (* Exercise 7 *) let rec pow1 (x, n) = if n = 0 then 1 else x * pow1 (x, n -1) ;; let rec pow2 (x, n) = let square x_ = x_ * x_ in match n with 0 -> 1 | 1 -> x | n when n mod 2 = 0 -> square (pow2 (x, n/2)) | _ -> (square (pow2 (x, (n-1)/2))) * x ;; Printf.printf "pow1 -> %d\n" (pow1 (2, 10));; Printf.printf "pow2 -> %d\n" (pow2 (2, 10));; (* Exercise 8 *) let rec powi (x, n, res) = if n = 0 then res else powi (x, n-1, x * res) ;; Printf.printf "powi -> %d\n" (powi (2, 10, 1));;
Exercise 11-1,2
問題
Exercise11以下の関数を定義せよ.
1. Euclid の互除法で二整数の最大公約数を求める関数 gcd.
2. テキストの再帰的な定義で (n, m) を求める関数 comb.
自分の答え
open Printf (* Exercise 11-1 *) let rec gcd (m, n) = match (m, n) with (_, n) when n = 0 -> m | (m, n) when m mod n = 0 -> n | (_, _) -> gcd (n, m mod n) ;; let print_gcd (m, n) = let ret = gcd (m, n) in Printf.printf "(%d, %d) -> %d\n" m n ret ;; print_gcd (1071, 1029);; print_gcd (1029, 1071);; (* Exercise 11-2 *) let rec comb (n, m) = match (n, m) with (n, m) when n * m = 0 -> 1 | (n, m) when n = m -> 1 | (n, m) when m > n -> comb (m, n) | (_, _) -> comb (n-1, m) + comb (n-1, m-1) ;; let print_comb (n, m) = let ret = comb (n, m) in Printf.printf "comb (%d, %d) -> %d\n" n m ret ;; print_comb (6, 3);;
感想
- ガードを使うときにパターンが同じ場合はwhenだけつなげられるかな?と思ったけどダメでした
- 局所関数?でfunctionを使ったら動かなかったのにmatch..withで書いたら動いた。
- functionを使うときに引数を取ってしまっていた。match..withと形がに似ていておそらく直してなかったのだと思う。
はやく末尾再帰をすらすらと書けるようにしないと、OCamlのCの字にたどり着けない。
教えていただいたこと
id:camlspotter に添削をいただきました。
- match..with の直後のパターンの前に | があってもよく、これがあると見やすいともっぱらの評判(流行っている)
- if e then true else false ----> e に書き換えられるよね(たしかに)
- 数字の比較は (==) 使わないで (=) を使う。( == はポインタ比較)
参照
- パターンマッチにガード条件を加える:Rainy Day Codings:So-net blog
- 「ガードって使えるのかな?」と思って調べてみました
- Printf
- Printf.printfでタプルを表示するフォーマットはあるかな?と思ったんですがそんなに世の中甘くなかったです