091118
プログラミング in OCaml #8
プログラミング in OCaml (目次) - kengpong
(* 練習問題 5.2 次の関数を定義しなさい *) (* 1. 正の整数 n から 1 までの整数の降順リストを生成する downto1 *) let rec downto1 = function 0 -> [] | n -> n :: downto1 (n - 1);; (* 2. 関数 roman *) let rec roman dict n = match dict with [] -> "" | (n', s) :: rest when n >= n' -> s ^ roman dict (n - n') | (n', s) :: rest -> roman rest n;; (* 3. 与えられたリストのリストに対し、(内側の)要素数を返す nested_length *) let rec nested_length = function [] -> 0 | x :: rest -> (List.length x) + nested_length rest;; (* 4. 与えられたリストのリストに対し、内側のリストの要素を並べ変えたリストを返す concat *) let rec concat l = List.fold_left (@) [] l;; (* 5. zip *) let rec zip l1 l2 = match (l1, l2) with | (x :: xrest, y :: yrest) -> (x, y) :: zip xrest yrest | (_, _) -> [];; (* 6. unzip *) let rec unzip = function [] -> ([], []) | (x, y) :: rest -> let (xrest, yares) = unzip rest in (x :: xrest, y :: yrest);; (* 7. リストとリストの要素上の述語 p を満すすべての要素のリストを返す filter *) let rec filter f = function [] -> [] | x :: rest when f x -> x :: filter f rest | x :: rest -> filter f rest;; (* 8-1. 先頭から n 番目までの要素からなる部分リストを取りだす take *) let rec take n = function x :: rest when n > 0 x :: take (n - 1) rest | _ -> [];; (* 8-2. 先頭から n 番目までの要素を抜かした部分リストを取りだす drop *) let rec drop n = function x :: rest when n > 0 -> drop (n - 1) rest | l -> l;; (* 9. (空でない) リストのなかから最大値を返す max_list *) let max_list = function x :: [] -> x | x :: rest -> let y = max_list rest in if x > y then x else y;;
日が空いた上に、 半分寝てるような状態でやったので、いろいろと駄目っぽいなー。
気がついた点として
- concat の効率が悪い
- さらっと List モジュール使ってるけど、いいの?
- ガードと if 式の使いわけが気分で分けてる感じになっちゃってるけど、どうしよう。
とかがあるかなー。
とりあえずは動けばあんまり気にしない方向で!*1
*1:もちろんツッコミ等は大歓迎です
091112
プログラミング in OCaml #7
プログラミング in OCaml (目次) - kengpong
(* 練習問題 4.1 uncurry を定義 *) let curry f x y = f (x, y);; let average (x, y) = (x +. y) /. 2.0;; let curried_avg = curry average;; let uncurry f (x, y) = f x y;; let avg = uncurry curried_avg in avg (4.0, 5.3);; (* 練習問題 4.2 repeat を使って fib を定義 *) let rec repeat f n x = if n > 0 then repeat f (n - 1) (f x) else x;; let fib n = let (fibn, _) = repeat (fun (x, y) -> (x + y, x)) n (0, 1) in fibn;; (* 練習問題 4.6 関数 fun x y -> y を コンビネータ s と k を組合せて表現 *) let f x y = k (s k k) x y;;
うーん、だんだん難しくなってきたなー。
4.6 は全くわからなかったのでカンニング。
答え見てもパッと見だと全くわからないところが面白い
091110
プログラミング in OCaml #6
プログラミング in OCaml (目次) - kengpong
(* * 練習問題 3.13 * 練習問題 3.7 の pow 関数をカリー化して定義せよ。 *) let rec pow x n = if n < 2 then x else pow x n - 1 *. x;; (* 第一引数が指数になるように定義し、3乗する関数 cube を部分適用で定義 *) let rec pow n x = if n < 2 then x else pow (n - 1) x *. x;; let cube = pow 3;; (* 第二引数が指数の場合に、cube を定義するにはどうするか *) let rec pow x n = if n < 2 then x else pow x n - 1 *. x;; let cube = (fun x -> pow x 3);; (* 練習問題 3.14 *) (* え?定積分?なにそれうまいの? *) (* 練習問題 3.15 以下の型の適当な関数を定義 *) (* int -> int -> int -> int *) let foo i j k = i + j + k;; (* (int -> int) -> int -> int *) let bar (f : int -> int) i = f i;; (* (int -> int -> int) -> int *) let baz (f : int -> int -> int) = f 1 2;;
Newton-Raphson法のあたりは華麗にスルーした。いつか倒すリストに入れておいてやろう!
適当な関数を定義が適当すぎるのはこれで良いの?
なんか問題読み間違えてる気もするなぁ。
091109
プログラミング in OCaml #4
プログラミング in OCaml (目次) - kengpong
(* * 練習問題 3.7 * x は実数、n は0 以上の整数として、x**n を計算する関数 pow (x, n) を * 以下の2通りで定義しなさい。 *) (* 1. 計算中に pow の再帰呼び出しをn回伴う定義 *) let rec pow (x, n) = if n < 2 then x else pow(x, n - 1) *. x;; (* 2. 計算中の pow の再帰呼び出しが約 log2n 回ですむ定義 *) let rec pow(x, n) = if n = 0 then 1.0 else if n mod 2 = 0 then pow(x *. x, n / 2) else pow(x *. x, n / 2) *. x;; (* 練習問題 3.8 指数関数を iterpow という名前で反復的的に定義しなさい *) let pow(x, n) = let rec iterpow(x, n, res) = if n < 1 then res else iterpow(x, n - 1, res *. x) in iterpow(x, n, 1.0);;
3.7-2 はカンニングした。冪乗 - Wikipediaにあるバイナリ法と呼ばれる手法らしい。
3.8 はすごく不安。こういう事で良いのか?
プログラミング in OCaml #5
プログラミング in OCaml (目次) - kengpong
(* 練習問題 3.11 以下の関数を定義 *) (* 1. ユークリッドの互除法で二整数の最大公約数を求める関数 gcd *) let rec gcd(a, b) = if a mod b = 0 then b else gcd(b, a mod b);; (* 2. 本文中で与えた再帰的な定義で nCm を求める関数 comb *) let rec comb(n, m) = if m = 0 || n = m then 1 else comb(n - 1, m) + comb(n - 1, m - 1);; (* 3. 末尾再帰的関数を使ってフィボナッチ数を計算する iterfib *) let fib n = let rec iterfib(i, x, y) = if n = i then x else iterfib(i+1, x + y, x) in iterfib(1, 1, 0);; (* 4. 与えられた文字列の中で ASCII コードが最も大きい文字を返す max_ascii *) let max_ascii str = let rec _max_ascii(i, max) = if i = String.length str then max else let len = int_of_char str.[i] in _max_ascii(i+1, if len > max then len else max) in char_of_int (_max_ascii (0, 0));;
1, 2 については、本当にそのまま書いたという感じ。おもすれー。
3 はちょっと悩んだ。まだまだ関数型の考えかたに慣れ無いなー。
後回しにしていたけども、標準的なコーディング規約ぐらいは知っておこうか。
インデントの数とか位置とか、カッコの前後のスペースとか、若干悩んでしまう。
あとは名前の付け方とかも慣例を知りたいなー。 _max_ascii みたいな名前ってどうよみたいな。
091107
プログラミング in OCaml (目次)
前置き
前回の日記ではてな市民になれたようで、ここいらで一発ちゃんと日記書くかーというところに届きました プログラミング in OCaml。
ちょうど良いので、この本の練習問題を連載していく事にしました。どこまで続くかな?
方針
という感じで進めていこう。
ただ、問題文が長くて打つのめんどくさい時は、勝手に端折っていくようになるだろうと予想。
というわけで
いつも通りツッコミとかお待ちしておりますので、勝手に添削なりコメントなりよろすくおねがいします!
追記
あー、そういえば、、
どこまでが引用で、どこからがまずいのかとか良くわかっていないので、そういった意味でのツッコミとかもあったら教えてください!
プログラミング in OCaml ~関数型プログラミングの基礎からGUI構築まで~
- 作者: 五十嵐淳
- 出版社/メーカー: 技術評論社
- 発売日: 2007/11/29
- メディア: 単行本(ソフトカバー)
- 購入: 11人 クリック: 169回
- この商品を含むブログ (50件) を見る
プログラミング in OCaml #0
プログラミング in OCaml (目次) - kengpong
(* 練習問題 3.1 *) (* USドルを受け取って円に換算する関数 *) let dollar2yen dollar = let rate = 114.32 in int_of_float (floor (dollar *. rate +. 0.5)) ;; (* 円を受け取ってUSドルに換算する関数 *) let yen2dollar yen = let rate = 114.32 in (floor ((float_of_int yen) *. 10. /. rate +. 0.5)) /. 10. ;; (* USドルを受け取って文字列を返す関数 *) let dollar2yen_string dollar = let dollar_string = string_of_float dollar in let yen_string = string_of_int (dollar2yen dollar) in dollar_string ^ " dollars are " ^ yen_string ^ " yen." ;; (* 文字を受け取ってアルファベットなら大文字に、その他はそのまま返す関数 *) let capitalize c = let c_int = int_of_char c in if c_int > 96 && c_int < 123 then char_of_int (c_int - 32) else c ;;
プログラミング in OCaml #1
プログラミング in OCaml (目次) - kengpong
(* 練習問題3.2 *) (* * 式 b1 && b2 を if 式と true, false, b1, b2 のみを用いて、同じ意味になるようにする。 * 式 b1 || b2 についても同様に。 * 簡単過ぎるようであれば if の使用を一度までにする。 *) let before b1 b2 = b1 && b2;; let after b1 b2 = if b1 then if b2 then true else false else false ;; let more b1 b2 = if b1 then b2 else b1 ;; (* b1 || b2 についても同様に *) let before b1 b2 = b1 || b2;; let after b1 b2 = if b1 then true else if b2 then true else false ;; let more b1 b2 = if b1 then b1 else b2 ;;
if 式一度ってのは、これやるまであまり考えてなかった発想だなー。
プログラミング in OCaml #2
プログラミング in OCaml (目次) - kengpong
(* 練習問題3.3 *) (* 式 b1 && b2 を || と not と b1, b2 のみを用いて同じ意味になるように書く。*) let before b1 b2 = b1 && b2;; let after b1 b2 = (not (not b1 || not b2));; (* 式 b1 || b2 を && と not と b1, b2 のみを用いて同じく。*) let before b1 b2 = b1 || b2;; let after b1 b2 = (not (not b1 && nob b2));;
しばらく考えて駄目っぽかったのでカンニングしたところ、ド・モルガンの法則 - Wikipediaとかいう奴らしい。
プログラミング in OCaml #3
プログラミング in OCaml (目次) - kengpong
(* 練習問題3.6 次の関数を定義せよ*) (* 1. 2実数の相乗平均をとる関数 geo_mean *) let geo_mean (x, y) = sqrt(x *. y);; (* * 2. 名前(文字列)、身長(実数)、体重(実数)の組を受け取って * 「○○さんは痩せています」などの文字列を返す関 bmi *) let bmi (name, height, weight) = let num = weight /. (height ** height) in let status = if num > 30. then "overweight" else if num > 25. then "normal" else "underweight" in name ^ ":" ^ status ;; (* 3. 任意の整数 x, y に対し、 f (sum_and_diff (x,y)) が (x,y) を返す関数f *) let sum_and_diff (x, y) = (x + y, x - y);; let f (x, y) = ((x + y) / 2, (x - y) / 2);;
2. の問題は、最初日本語で出力しようと思ったのだけど、なんか上手くいかなかった。
その辺の日本語環境回りの事とかは、後々出てきたりするのかな?
