OCaml

-1 を 10 で割ったあまりは?

どう書く?org のこのお題,はじめはHaskellで書いた。 modular n l h = l + n `mod` (h - l + 1) すでに投稿があったのでOCamlで書き直したんだけど,そのまま移植したんではうまくいかない。 # let modular n l h = l + n mod (h - l + 1);; val modular :…

練習問題 10.3 fold コマンド

プログラミング in OCaml ~関数型プログラミングの基礎からGUI構築まで~のp.215より。 wc コマンドはなんか難しいのでこっちを先に。 UNIX の fold コマンドは,ファイル名の列を引数として,その内容を,長い行を複数の短い 行(デフォルトでは80文字)に分…

練習問題 10.1

プログラミング in OCaml ~関数型プログラミングの基礎からGUI構築まで~のp.215より。 UNIXの cat コマンドは,ファイル名の列を引数として,その内容を順次表示する(標準出力 に書き込む)ものです。これを OCaml で実装し,実行可能ファイルを作成しなさ…

unfold で1から10までのリスト

unfold を覚えたので,こないだの1から10までのリストを unfold を使ってやってみる。 と思ったら unfold が見つからないのでまずはその定義から。 # let rec unfold f init = match f init with Some (a, b) -> a :: unfold f b | None -> [] ;; val unfold…

Sys.argv

コマンドライン引数は Sys.argv に配列として格納される。インデックス0がプログラム名で,以下引数の数だけ続く。 インデックス0を出力する例: let () = print_endline Sys.argv.(0) ^o^ >ocamlc -o argv.exe argv.ml ^o^ >argv argvインデックス1を出力す…

Array.iter

Array.iter は配列に対して 'a -> unit 型の関数を順に適用する関数。List.iter の配列版。これを使えばコマンドライン引数の数だけ繰り返せる。 let () = Array.iter (fun s -> print_endline s) Sys.argv ^o^ >argv2 foo bar buz argv2 foo bar buz

インターフェイスファイル

ソースファイル(=モジュール)と同名で拡張子が .mli のファイルを用意しておくことで,モジュールにシグネチャを与えることができる。 前にも例に挙げた Table モジュールを例にとると, table.mli type ('a, 'b) t val empty : ('a, 'b) t val add : 'a -…

コンパイラがcmiを探すディレクトリ

次のディレクトリを順に検索する。 ocamlc コマンドを起動したディレクトリ ocamlc コマンドの -I オプションで指定したディレクトリ 標準ライブラリのディレクトリ

Problem 2

今日は Problem 2。フィボナッチ数列のうち4,000,000以下で偶数のみを合計せよ,という問題。cf. http://projecteuler.net/index.php?section=problems&id=2Haskell ではやってる人がいるので,OCaml でやってみた。 let fibs_under_n n = let rec fibs a b …

1から10までのリスト

って OCaml ではどう書けばいいんだろう。 Haskell では簡単に [1..10] と書ける。 Prelude> [1..10] [1,2,3,4,5,6,7,8,9,10]これなら10といわずいくつまででも簡単だ。だけど OCaml こういう書き方はできないらしい。 # [1..10];; Characters 4-6: [1..10];…

分割コンパイル

ソースファイルは1つじゃなくてもいい。次の例では,fact関数を定義している fact.ml と,それを呼び出す main.ml に分けている。fact.ml let rec fact n = if n = 0 then 1 else n * fact (n-1) main.ml let () = print_int (Fact.fact 5) OCamlではファイ…

コンパイラ

OCaml のコンパイラには ocamlc と ocamlopt の二つがある。 ocamlc バイトコードを出力。機種非依存。 ocamlopt ネイティブコードを出力。機種依存。 ocamlc の出力したバイトコードはどの機種でも動作するけど,ただし,バイトコートインタプリタというプ…

mainに相当する関数

OCamlにはない。 代わりに, let () = ...とか let _ = ...とかするみたい。 let hello () = print_string "Hello world!\n" let () = hello () ^o^ >ocamlc -o hello.exe hello.ml ^o^ >hello Hello world!

コラッツ予想

cf. Way of My Life - コラッツ予想Haskell と OCaml でやってみた。 与えられた数から1になるまでをリストで返す。 collatz :: Int -> [Int] collatz 1 = 1 : [] collatz n | n `mod` 2 == 0 = n : collatz (n `div` 2) | otherwise = n : collatz (n * 3 +…

データの整列

どう書く?.orgに投稿した。cf. データの整列sort_by_dic が辞書順に整列する関数,sort_by_dis が距離の昇順に整列する関数。 type point = Point of float * float let compare_point a b = match (a, b) with (Point (x1, y1), Point (x2, y2)) -> if x1 …

モジュールの定義

モジュール(正確にはストラクチャ)の定義は次のようにして,struct と endo のあいだに各種定義の書く。 # module Tree = struct type 'a t = Lf | Br of 'a * 'a t * 'a t let rec size = function Lf -> 0 | Br (_, left, right) -> 1 + size left + siz…

シグネチャ

前のエントリの例のようにシグネチャをコンパイラに推論させるのではなく,自分で書くこともできる。そのとき,モジュールの外部には公開したくない関数や,定義した型の詳細を隠蔽することもできる。一般には: シグネチャを定義する そのシグネチャをモジ…

シグネチャ(その2)

前エントリではモジュールの定義とシグネチャを与えるのを別にしたけど,いっぺんにすることもできる。というかその方が一般的なのかな。こんな感じ。 module Table1 : TABLE1 = struct ... end;;

open宣言

モジュールの関数を使うときには[モジュール名].[関数名]とするけど,open宣言をすればモジュール名をつけなくても使えるようになる。 # map (fun x -> x * x) [1;2;3;4];; Characters 0-3: map (fun x -> x * x) [1;2;3;4];; ^^^ Unbound value map # open …

FizzBuzz

出力も覚えたし書いてみた。 let fizzbuzz x = let f = if x mod 3 = 0 then "Fizz" else "" in let b = if x mod 5 = 0 then "Buzz" else "" in let fb = f ^ b in if fb = "" then string_of_int x else fb ;; let () = for i = 1 to 100 do print_endline…

練習問題8.6

本文中の関数 whle を参考にして,for式相当の機能を実現する再帰関数を定義しなさい。 こんなんでいいのかな。 # let rec fr frm t body = if frm <= t then begin body frm; fr (frm + 1) t body end ;; val fr : int -> int -> (int -> 'a) -> unit = <fun> # </fun>…

練習問題8.1

本文中でもふれたように,ref型は以下のように定義された,1フィールドの書き換え可能な レコードです。 type 'a ref = { mutable contents : 'a };; 関数 ref,前置演算子 !,中置演算子 := の定義をレコードに関連した操作で書きなさい。 こうかな。 let r…

練習問題8.2

与えられた参照の指す先の整数を1増やす関数 incr を定義しなさい。 # let incr x = x := !x + 1;; val incr : int ref -> unit = <fun> # let x = ref 3;; val x : int ref = {contents = 3} # incr x;; - : unit = () # !x;; - : int = 4</fun>

練習問題8.4

参照と繰り返しの構文(while,for)を使ってフィボナッチ数を求める関数を定義しなさい。 # let fib n = let fibs = ref (1, 1) in let i = ref 1 in while !i < n do fibs := (snd !fibs, fst !fibs + snd !fibs); i := !i + 1 done; snd !fibs ;; val fib…

チャネルを使った入出力

チャネルっていうのは,ファイルディスクリプタみたいなものだと思っておけば良さそう。 入力用には open_in と close_in を使う。 こういうファイル members.txt があったとして: ^o^ >type members.txt andy bill charlieファイルから入力する例。 # let i…

ファイルに追加出力する

open_out を使ってファイルを開くと,そのファイルがすでに存在した場合,中身を消去してしまう。既存のファイルに追加するには,open_out_gen を使ってチャネルを作る*1。 # let outfile = open_out_gen [Open_wronly; Open_append; Open_text] 0o666 "C:/h…

繰り返しのための高階関数

繰り返しの構造を関数(再帰関数)にすることもできる。 # let rec whle condition body = if condition () then begin body (); whle condition body end ;; val whle : (unit -> bool) -> (unit -> 'a) -> unit = <fun>condition () が真であるあいだ body を繰</fun>…

制御構造

入出力など,副作用のある計算をするときには式を評価する順番が重要になる。OCaml にもそのための制御構造(control structure)がある。 逐次実行 1つの方法は let 〜 in を使うこと。let 以下が評価された後に in 以下が評価される。 # let () = print_st…

多相性と書き換え可能データ

let で名前の付けられる式が値でない場合,多相性に制約がつくことがある。値でないとはたとえば参照などだ。 # let x = ref [];; val x : '_a list ref = {contents = []}x は参照で,中身は空のリストだ。空だから何のリストでもいい(多相)はずで,型も …

配列

配列はリストと似ているけど 長さが生成時に固定される 各要素に直接アクセスできる 書き換え可能 という点で違う。各要素は同じ型でないといけないのはリストと同じ。生成: # let ary = [| 1; 2; 3; 4; 5 |];; val ary : int array = [|1; 2; 3; 4; 5|] # …