OCaml 入門その1  OCamlの基本と型推論

## 関数型言語

関数型言語 => プログラムの実行 = 式の実行
式の実行 => 式を評価(eval)して値(value)を得ること

![ocaml_eval_expression.png](https://qiita-image-store.s3.amazonaws.com/0/4428/e7637632-92b4-b764-b0ce-de6aae939aa4.png "ocaml_eval_expression.png")


## 基本データ型

### 整数型 (int)
プリフィックス
`0b` で2進数
`0o` で8進数
`0x` で16進数

```
- : int = 351
# 12345;;
- : int = 12345
# 0o523;;
- : int = 339
# 0xffff;;
- : int = 65535
```

### 実数型 (float)
少数も扱える。
e表記も可能。

```ocaml
# 3.141;;
- : float = 3.1415
# 1.04e10;;
- : float = 10400000000.
# 25e-15;;
- : float = 2.5e-14
```

### 文字型 (char)
半角英数字(ascii文字) で1重引用符で囲む

```ocaml
# 'a';;
- : char = 'a'
# '\101';;
- : char = 'e'
# '\n';;
- : char = '\n'
```

### 文字列型 (string)
二重引用符で囲む。
`文字列.[添字]` で1文字を取り出せる。

```ocaml
# "string";;
- : string = "string"
# "string".[0];;
- : char = 's'
```

### 型変換

X型からY型へ変換する関数は **Y_of_X** という命名規則がある。

```ocaml
# float_of_int 5;;
- : float = 5.
# int_of_float 5.;;
- : int = 5
- # string_of_int 123;;
- : string = "123"
# int_of_string "123";;
- : int = 123
```

### 組
**(型名 * 型名...)**

```ocaml
# (1, 2);;
- : int * int = (1, 2)
# ('a', 1, "str", 4.3);;
- : char * int * string * float = ('a', 1, "str", 4.3)
# ((1, 2), ('a', "str"));;
- : (int * int) * (char * string) = ((1, 2), ('a', "str"))
```

## 変数定義(束縛)

### let定義 (let defenition)

**let 変数名 = 式**

```ocaml
# let hoge = 1;;
val hoge : int = 1
```

同時定義可能

**let 変数名 = 式1 and 式2**

```ocaml
# let a = 1 and b = 2;;
val a : int = 1
val b : int = 2
```

## 関数定義

**let 関数名 パラメータ = 式**

```ocaml
# let twice s = s ^ s;; 
val twice : string -> string = <fun>
```

パラメータを囲む `()` は省略可能。


### let式 (let expression)
`let定義` とは違う。
関数内の一時的に使う変数(**局所変数**)を定義するための式。

**let 変数 = 式1 in 式2**

```ocaml
# let four_times s =
  let twice = s ^ s in
  twice ^ twice;;
val four_times : string -> string = <fun>
```

### 再帰定義

**let rec** で定義する。
`rec` を使うと関数定義内で、定義中の関数の名前を参照できるようになる。

階乗の例

```ocaml
# let rec fact x =
    if x <= 1 then 1 else x * fact (x - 1);;
val fact : int -> int = <fun>
# fact 5;;
- : int = 120
```

### 相互再帰
二つ以上の関数がお互いを呼び合うスタイルの再帰定義。

**let rec 関数名1 パラメータ1 = 式1 and 関数名2 パラメータ2 = 式2 and ...**

```ocaml
# let rec even n =
    match n with
    | 0 -> true
    | x -> odd (x-1)
  and odd n =
    match n with
    | 0 -> false
    | x -> even (x-1);;
val even : int -> bool = <fun>
val odd : int -> bool = <fun>

# even 10;;
- : bool = true
# even 3;;
- : bool = false
# odd 3;;
- : bool = true
# odd 10;;
- : bool = false
```

### 無名関数
**fun パラメータ = 式**

`let f パラメータ = 式` は `let f = fun パラメータ = 式` の糖衣構文。
`fun` は可能な限り先まで関数定義だと認識するため、必要なところまで `()` で区切ると良い。


### 高階関数
関数を引数に取る関数の定義

```ocaml
# let twice f x = f (f x);;
val twice : ('a -> 'a) -> 'a -> 'a = <fun>
# twice (fun x -> x * x) 3;;
- : int = 81

# let fourth x = 
    let square y = y * y in
    twice square x;;
val fourth : int -> int = <fun>
# fourth 3;;
- : int = 81
```

### 関数のカリー化
```ocaml
# let concat_curry s1 = fun s2 -> s1 ^ s2 ^ s1;;
val concat_curry : string -> string -> string = <fun>
# concat_curry "a";;  (* 部分適用 *)
- : string -> string = <fun>
# (concat_curry "a") "b";;
- : string = "aba"
```

#### カリー化の糖衣構文
以下の定義は

```ocaml
let concat_curry s1 s2 = s1 ^ s2 ^ s1;;
```

以下と同義

```ocaml
let concat_curry s1 = fun s2 -> s1 ^ s2 ^ s1;;
```

つまり、パラメータを並べると

```ocaml
# let fuga x y z = x + y + z;;
val fuga : int -> int -> int -> int = <fun>
```

実際には以下のように展開されている。

```ocaml
# let hoge x = fun y -> fun z -> x + y + z;;
val hoge : int -> int -> int -> int = <fun>
```

**関数適用は左結合** なので、以下のように展開される。

```ocaml
f x y z => (((f x) y) z)
```

**関数型構築子は右結合** なので、以下のように解釈する。

```ocaml
int -> int -> int -> int = <fun>
は
int -> (int -> (int -> int)) = <fun>
```

### 演算子の定義
中置演算子はカリー化された関数として定義されている。

```ocaml
# (+);;
- : int -> int -> int = <fun>
# (+) 1 2;;
- : int = 3
```

自分で演算子を定義する場合は

1. 前置演算子
	- 1引数関数として定義する
2. 中置演算子
	- 2引数(カリー化)関数として定義する

演算子の定義に使える文字種は制限されているので注意する。

## 型推論
比較演算子(=など)は整数型・実数型など複数の型で使える => **多相性(ポリモーフィズム)**を持つ。
多相性がある型システムを **多相的型システム** と呼ぶ。

### 型スキーム・パラメトリック多相
型の出現パターンを示す、変数のようなもの。
`'a` や `'b` のように表現される。

```ocaml
# let twice f x = f (f x);;
val twice : ('a -> 'a) -> 'a -> 'a = <fun>
# let first (x, y) = x;;
val first : 'a * 'b -> 'a = <fun>
```

実行の際に、OCaml の型システムが型スキーム(`'a`など)を具体化(具体的な型に当てはめる)する。
型情報をパラメータ化することによる多相性を **パラメトリック多相** と呼ぶ。

### 型変数の一般化
型変数(`'_a`など)を一般化(`'a`のような型スキーム)するための条件の __1つ__ は以下。

**定義の右辺の式がそのまま値であれば型変数を一般化してよい**

値として扱われるもの => 計算を必要としない式
例として

1. 関数の宣言
2. 定数

値に評価されるために、計算が必要となる式は値として扱われない。

```
(* 恒等関数を定義する *)
# let id x = x;;
val id : 'a -> 'a = <fun>

(* '_a は型スキームではない 
   id id は値になるためには何か実引数が必要で、計算が必要。
*)
# let id' = id id;; 
val id' : '_a -> '_a = <fun>

(* 
   こっちは型スキーム
   パラメータ x を追加することで id' は関数定義となる。
*)
# let id' x = id id x;;
val id' : 'a -> 'a = <fun>
```



## 参考文献
![](http://image.gihyo.co.jp/assets/images/cover/2007/9784774132648.jpg)

[プログラミング in OCaml](http://gihyo.jp/book/2007/978-4-7741-3264-8)

非常に分かりやすく、OCamlを学ぶ際にオススメです。