Install OCaml
# macOS
$ brew install ocaml
$ brew install opam
;;
-> 入力の区切り
- 整数同士の四則演算は
+
, -
, *
, /
, mod
- 実数同士の四則演算は
+.
, -.
*.
, /.
- 実数のべき乗は
**
(べき乗は実数のみに用意されている)
- 文字列の連結は
^
- 論理演算は
not
, &&
, ||
- 比較演算は
>
, >=
, ==
, <
, <=
-.
-> 正負を入れ替える単項演算子
- 変数定義 ->
let 変数名 = 式 ;;
- 変数の先頭はアルファベット小文字
- 関数定義 ->
let 関数名 引数 = 式 ;;
- 引数が複数の場合 ->
let 関数 x y ;;
val x : A -> B = <fun>
-> 「float型の値を受け取り、float型の値を返す」
- 引数が複数の場合 ->
val x : A -> B -> C = <fun>
- 右に結合する(一つ目の引数にAを取り、二つ目の引数にBを取り、結果としてCを返す)
- xはfloat型の関数のため、引数にintを渡すことはできない
- 型に対するOCamlインタプリタの役割は
- 引数に負の数を渡す場合は()で囲む
- 関数に望まれる入力と出力の例を作成
- 実行可能なテストプログラムを作成
# function.ml
let function x = x
let test1 = function x = y
- インタプリタにテストファイルを読み込むだけでテストが自動的に実行される
- 式同士の型を揃える
- 式中にif文を埋め込むことができる
let 関数 x = x * (if true then 1 else 100)
- 全ての場合についてテストを用意する
- 閾値をテストする
- 先に条件式を書き、条件が特定できたらthen節、else節を書く
- いくつかのデータをまとめて一つのデータにしたもの -> 組
(3.14, 2.71 ) ;;
- : float * float = (3.14, 2.71)
- 要素の型の組み合わせは異なっていても可、要素数はいくつでも可
((3.14, "a"), 3.14) ;;
- : (float * string) * float = ((3.14, "a"), 3.14)
- 複数のデータから成るデータの中身を取り出す -> パターンマッチ
match (3, 5) with
(a, b) -> a + b ;;
- : int = 8
let add pair = match (a, b) with
(a, b) -> a + b ;;
# 上記と同じ
let add (a, b) = a + b ;;
- パターン変数はお互いに異なっている必要がある
- 複数のデータが一つのデータになる場合に組を使用する
- 構造データが入力された場合、中身を取り出すmatch文を書く
- テストでmatchの構文があっていることを確認
{ フィールド1 = パターン変数1 ; フィールド2 = パターン変数2 ; フィールド3 = パターン変数3 ; ...}
type student_t = {
name : string; (* 名前 *)
score : int; (* 点数 *)
grade : string; (* 成績 *)
}
let notice student = match student with
{ name = n; score = s; grade = g; } ->
n ^ "さんは" ^ string_of_int s ^ "点で、成績は" ^ g ^ "です"
- n, s, gがパターン変数
- typeのフィールド名は一意であること
- 再帰するケース
- 再帰しないケース(基本ケース...リストが空の場合)
- 再帰関数の場合は
let
の後にrec
を付加
first :: rest
の場合、再帰できるのは自己参照しているrestのみ
let 変数名 = 式1
までを一区切りとして考える
(fun x -> x + 1) 5 ;;
- : int = 6
let add_one = (fun x -> x + 1) 5 ;;
val add_one : int = 6
- 関数の後に引数を置く関数(普通の関数)
- infix関数 ->
+
のように関数の前後に引数を置く関数
()
で囲むことによってprefix関数に変換することができる
- 自明に答えが出るケースの条件
- 自明に答えが出るケースの式
- それ以外のケースの式
- 自明に答えが出るケースはどのような場合か
- その場合の答えは何か
- 部分問題はどのように作れるか
- 部分問題の結果から全体の結果を得るにはどうすれば良いか
- 欠落している情報を補うために導入される引数(情報を貯めておくために使う)
- アキュムレータを使った関数は局所的に補助関数として使用され、特定の初期値を要とする
type team_t = Red | White
# RedやWhiteは構成子
# 構成子は必ず大文字から始める
let team_string team = match team with
Red -> "赤"
| White -> "白"
type year_t = Meiji of int
| Taisho of int
| Showa of int
| Heisei of int
| Reiwa of int
# 引数は「構成子 of 型」という形で表現する
Reiwa (1)
Empty ;;
# -> 空の木
Leaf (3);;
# -> int 3を格納した葉
Node (Empty, 7, Leaf(3)) ;;
# -> int 7を格納し、左右にそれぞれ空の木とint 3を格納した葉を持つ節
# -> 左右の葉が自己参照になっている
- 型に対応するmatch文を書く
- 自己参照するケースが再帰呼び出しのケースに対応する
- 自己参照する数だけ再帰呼び出しされる
type 'a option = None
| Some of 'a
raise XXXError
-> 例外を発生させる
exception
XXXError -> 例外を定義する
exception XXXError of 引数の型
try 式 with
-> 例外処理(例外が発生しなければ式の結果が返る)
module モジュール名 = struct
# 本体
end
- シグネチャ = モジュールのインタフェース定義(抽象データ型)
module type シグネチャ名 = sig
# 本体
end
module モジュール名 : シグネチャ名 = struct
# 本体
end
module モジュール名 : sig
# シグネチャ本体
end = struct
# モジュール本体
end
- 何も引数に取らず、何も意味のある値を返さない型
- 返される値は()(ユニット: 意味のない値)
- 左から順に実行しては返り値を捨て、最終的に右端の式を実行してその結果を返す
- 式nよりも前に実行する式の返り値がunitでない場合、警告が表示される
- 一度定義された参照型は同じメモリ番地を参照し続ける(参照型に対して行われる操作は常に破壊的)
- 基本的に全てのレコードの全てのフィールドがイミュータブル
- 型を定義する際、フィールド名の手前に
mutable
をつけることでミュータブルなフィールドになる
type = {
mutable hoge : string; # ミュータブル
fuga : string; # イミュータブル
}
- ミュータブルなフィールドに対しては
<-
で値を再代入できる
- 配列の要素の型は全て同じであること
- 配列の要素を取り出す
let arr = [|1; 2;|]
Array.get arr 0
# => - : int = 1
arr.(0)
# => - : int = 1
let arr = [|1; 2;|]
Array.set arr 0 0
# => - : unit = ()
a
# => - : int array = [|0; 1; 2;|]
arr.(3) <- 3
# => - : unit = ()
a
# => - : int array = [|0; 1; 2; 3;|]