2008-01-01から1年間の記事一覧

シグネチャ

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

シグネチャ(その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|] # …

書き換え可能なデータ構造:文字列

実は,文字列は書き換えが可能。たとえば次のような文字列があったとして: # let s = "life";; val s : string = "life" # s;; - : string = "life"次のように書き換えができる。 # s.[2] <- 'k';; - : unit = () # s;; - : string = "like"新しい値ができる…

構造的等価性と物理的等価性

2つのデータを比べたとき,「値として等しいこと」を構造的等価性(structural equality)という。「値として」だけでなく,メモリ上の同じ位置を占めていることを物理的等価性(physical equality)という。 OCaml には構造的等価性を調べる演算子 = と物…

書き換え可能なレコード

レコードを宣言するときにフィールド名の前に mutable キーワードをつけることで,書き換え可能にすることができる。 # type teacher = {name : string; mutable office : string};; type teacher = { name : string; mutable office : string; }これで offi…

参照

書き換え可能なレコードの特殊な場合で,フィールド1つだけを持つ場合を伝統的に参照(reference)という。参照には特別な書き方がある。 まず,参照の生成には ref 関数。 # let p = ref 4;; val p : int ref = {contents = 4}ref は初期値を引数にとって…

書き換え可能なデータ構造

OCaml には書き換え可能なデータ構造がある。 書き換え可能レコード(mutable record) 参照(reference) 配列(array)

exn型,exception宣言

Not_found とか Division_by_zero とかいう例外は,じつは exn型のコンストラクタ。例外コンストラクタと呼ぶ。 コンストラクタの型を見ると # Division_by_zero;; - : exn = Division_by_zeroexn型であることがわかる。同様に raise の型も。 # raise;; - :…

練習問題 7.2

整数リストの要素すべての積を返す関数 prod_list を定義しなさい。リスト要素の一つでも 0 が含まれている場合には,prod_list の適用結果は常に 0 になるので,例外処理を使用 して,0 を発見したら残りの計算を行わずに中断して 0 を返すように定義しなさ…

例外を発生させる raise

OCaml には例外処理の仕組みがある。例外を発生させるには raise を使う。raise は例外の名前を引数にとる。 fact関数の引数が負の時に例外を発生する例: # let rec fact n = if n < 0 then raise (Invalid_argument "fact: negative argument") else if n =…

例外を処理する try

発生した例外を捕捉して処理するのが try。 # try fact (-2) with Invalid_argument _ -> 0;; - : int = 0 # try fact 3 with Invalid_argument _ -> 0;; - : int = 6match によるパターンマッチングに似ている。まず try と with に囲まれた部分を評価し,…

ヴァリアントの応用:多相的ヴァリアント

多相的関数が型情報をパラメータ化できるのと同じように,ヴァリアントの定義の一部をパラメータ化することができる。 # type 'a mylist = Nil | Cons of 'a * 'a mylist;; type 'a mylist = Nil | Cons of 'a * 'a mylist'a がパラメータ化された部分。この…

多相的レコード

多相的な定義はレコードでもできる。次の定義は,既存のデータに「位置情報」を付け加える,というもの。 # type 'a with_location = {loc_x : float; loc_y : float; body : 'a};; type 'a with_location = { loc_x : float; loc_y : float; body : 'a; }文…

ヴァリアントの応用:列挙型

引数をとらないコンストラクタのみでヴァリアントを作れば,いわゆる列挙型になる。 # type color = Black | Blue | Red | Magenta | Green | Cyan | Yellow | White ;; type color = Black | Blue | Red | Magenta | Green | Cyan | Yellow | White

ヴァリアントの応用:再帰的ヴァリアント

type宣言において,コンストラクタの引数に今宣言しようとしているヴァリアントを使うことができる。つまり再帰的な宣言。 以下は0を含む自然数(というか正の整数)を表す型 nat を宣言する例。 ゼロは自然数である 自然数より1大きい数は自然数である これ…

ヴァリアント

type 宣言を使って宣言できるデータにはヴァリアントというのもある。おおざっぱに言うと「作り方に何種類か方法があるようなデータ」。Haskellでいう代数的データ型と同じと思っていいのかな。 たとえば次のようなものがヴァリアント。 # type figure = Poi…

ヴァリアントのコンストラクタ

コンストラクタの名前は: 一文字目が大文字 二文字目以降が英数字(A..Z, a..z, 0..9),アンダースコア(_)またはプライム(') であるような任意の長さの文字列。

レコード

レコードとはいくつかの値に名前を付けてまとめて扱えるようにしたデータ。構造体のようなもの。名前と値をあわせてフィールド,名前をフィールド名と呼ぶ。 新しいレコードの型を宣言するには type 宣言を使う。 # type student = {name : string; id : int…