-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Jun FURUSE
committed
May 27, 2016
1 parent
9c5e571
commit afdedf6
Showing
37 changed files
with
8,149 additions
and
0 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
Survival Guide in Desert with OCaml | ||
=========================================== | ||
|
||
この文章は OCaml の入門書ではありません。 | ||
|
||
OCaml の入門書は英語でも日本語でも既にいろいろと存在しています。 | ||
それらに書かれている事と同じ事を繰り返すのは、どうも時間の無駄かと思います。 | ||
|
||
この文章はその一歩先、独りで OCaml に乗って街を離れ、 | ||
死なずにオアシスに辿り着くための砂漠の地図を提供するつもりです。 | ||
|
||
既存のドキュメントに書かれている事は特に事情がない限り書かないこととします。 | ||
例えば、 OCaml コンパイラ一式をソースコードからインストールする場合には、 | ||
`INSTALL` というファイルを読めとは書きますが、その中の一歩一歩を辿ることは | ||
しません。なぜならそれは元の情報を劣化させて不正確にしたものを伝えること | ||
だからです。 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
============================= | ||
OCaml の真偽値型 ``bool`` | ||
============================= | ||
|
||
OCaml の真偽値の型は ``bool`` その *コンストラクタ* は ``true`` と ``false`` である。 ``true`` と ``false`` は小文字で始まっているが、変数ではなく、 ``Some`` や ``None`` と同じヴァリアントコンストラクタである。よってパターンの中に書ける:: | ||
|
||
(* true の数を数える *) | ||
function | ||
| (true, true) -> 2 | ||
| (true, false) | (false, true) -> 1 | ||
| (false, false) -> 0 | ||
|
||
``bool`` の文字列への出力 | ||
------------------------------- | ||
|
||
``Printf`` のフォーマット文字列中で ``%b`` を使うことで ``bool`` を出力させることができる:: | ||
|
||
# Printf.sprintf "%b" true;; | ||
- : string = "true" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,269 @@ | ||
============================= | ||
OCaml の数値型 | ||
============================= | ||
|
||
OCaml 数値型で標準で使えるものは、 | ||
``int``, ``float`` , ``int32``, ``int64``, ``native_int``, ``nat``, ``big_int``, | ||
``Complex.t`` | ||
の 8つ: | ||
|
||
``int`` | ||
|
||
標準の整数。 32bit 環境では 31bit, 64bit 環境では 63bit 符号付き整数。 | ||
|
||
``float`` | ||
|
||
倍精度(64bit)浮動小数点数。 IEEE 754 で言うところの double であって、float ではない。 | ||
|
||
``nativeint`` | ||
|
||
OS でサポートする基本整数幅を持つ。 | ||
32bit 環境では 32bit, 64bit 環境では 64bit 符号付き整数。 | ||
|
||
``int32`` | ||
|
||
32bit 符号付き整数。 | ||
|
||
``int64`` | ||
|
||
64bit 符号付き整数。 | ||
|
||
``nat`` | ||
|
||
num ライブラリで定義されている無限制精度自然数。 | ||
|
||
``big_int`` | ||
|
||
num ライブラリで定義されている無限制精度符号付数。 | ||
|
||
``Complex.t`` | ||
|
||
複素数。 単に float 二つ組で表現されている。 | ||
|
||
``int`` | ||
================================== | ||
|
||
OCaml で「整数」と言うと ``int`` を指す。 | ||
32bit 環境では 31bit, 64bit 環境では 63bit の符号付き整数。 | ||
「失われた 1bit」は GC が int とポインタを識別するために使われる。 | ||
この 1bit のおかげで ``int`` は box化されず、そのまま扱うことができるので | ||
「1bit」が失われていないが、box化が必要な ``nativeint`` と比べると高速に動作する。 | ||
|
||
定数の書式 | ||
---------------------------- | ||
|
||
通常の10進表記の他に、2進、8進、16進での表記が可能:: | ||
|
||
# 10;; | ||
- : int = 10 | ||
# 0b10;; | ||
- : int = 2 | ||
# 0o10;; | ||
- : int = 8 | ||
# 0x10;; | ||
- : int = 16 | ||
|
||
基本的な演算子 | ||
---------------------------- | ||
|
||
Pervasives に基本的は演算子 ``(+)``, ``(-)``, ``( * )``, ``(/)`` などが | ||
記載されているが、ほとんどがプリミティブ | ||
(``external`` 宣言による C関数呼び出し)である。 | ||
|
||
``int`` 掛け算の二項演算子 ``*`` を関数(CR jfuruse:?)として使う場合、 | ||
``(*)`` とスペース無しで書くとコメント様の文面と受け取られエラーになる。 | ||
必ず括弧と ``*`` の間に空白を入れること: ``( * )`` 。 | ||
|
||
環境によるサイズの違い | ||
---------------------------- | ||
|
||
``int`` は環境によってサイズが異なることに注意してほしい。その環境での ``int`` の | ||
上限と下限は ``Pervasives`` モジュール内の変数 ``max_int``, ``min_int`` に格納されている。 | ||
64bit アーキテクチャでの ``int`` を 32bit アーキテクチャの OCaml プログラムに渡して | ||
``int`` と解釈させると問題が発生する。(CR jfuruse: ほんと?) | ||
|
||
string_of_int x |> ... |> int_of_string の例 | ||
|
||
marshal の例 | ||
|
||
オーバーフロー、アンダーフロー | ||
---------------------------------- | ||
|
||
``max_int``, ``min_int`` を超える演算結果はオーバフローおよびアンダーフローを起こすが、 | ||
起こした事実は特にレポートされない。オバーフロー、アンダフローを起こしたか知りたい場合は | ||
自分で何かしら検査コードを書く必要がある:: | ||
|
||
# max_int + 1 = min_int;; | ||
- : bool = true (* オーバーフローが起こっている *) | ||
|
||
|
||
``float`` | ||
================================== | ||
|
||
倍精度(64bit)浮動小数点数。 IEEE754 や C で言うところの double である。 | ||
単精度(32bit)浮動小数点数(いわゆる IEEE754 や C で言うところの float) は | ||
OCaml には標準では用意されていない。 | ||
|
||
定数の書式 | ||
---------------------------------- | ||
|
||
OCaml では定数(どころか他の全てもそうだが)にはオーバーローディングがない。 | ||
そのため、 ``float`` はもし小数点以下が 0 だったとしても、 ``int`` との | ||
混乱を避けるため、小数点を付けなければならない:: | ||
|
||
# 1.23;; | ||
- : float = 1.23 | ||
# 1.0;; | ||
- : float = 1. | ||
# 42.;; | ||
- : float = 42. | ||
|
||
最後の ``42.`` のように少数点以下を書かない記法は他の言語ではエラーになる場合があるので注意が必要だ。 | ||
|
||
基本的な演算子 | ||
---------------------------- | ||
|
||
``int`` と同様、Pervasives に基本的は演算子 | ||
``(+.)``, ``(-.)``, ``( *.)``, ``(/.)`` などが宣言されている。 | ||
演算子の最後に ``.`` が付いていることに注意。 OCaml ではオーバーローディングが無いため、 | ||
``int`` の演算子 ``(+)``, ``(-)``, ``( * )``, ``(/)`` と同じ名前を | ||
``float`` 用の演算子名として用いることができない。そのための苦肉の策である。 | ||
|
||
後述の ``int`` 以外の演算子でも普通の四則演算子を使う も参照のこと。 | ||
CR jfuruse: link | ||
|
||
``nan`` | ||
---------------------------------- | ||
|
||
``float`` の演算は IEEE754 に準拠するため、無限値や ``nan`` などが存在する。 | ||
浮動小数点数がこれらの特殊な常態かどうかを調べるためには | ||
``Pervasives.classify_float`` を使う。 | ||
|
||
正確な文字列表現 | ||
---------------------------------- | ||
|
||
``float`` の内容を文字列に変換するには ``string_of_float`` を使うが、 | ||
この関数は小数点以下12桁までしか文字列に変換しない:: | ||
|
||
(* pervasives.ml *) | ||
let string_of_float f = valid_float_lexem (format_float "%.12g" f);; | ||
|
||
OCaml では ``float`` を完全に正確に文字列表現に変換することは難しいが、 | ||
桁数を上げることで誤差を少なくすることは可能である。例えば Sexplib では | ||
20桁まで出力を行なっている:: | ||
|
||
(* conv.ml of Sexplib *) | ||
let default_string_of_float = ref (fun n -> sprintf "%.20G" n) | ||
|
||
正確に ``float`` を外部に出力・記録したい場合は、その 64bit 表現をそのまま | ||
とり出さなければならない。 ``Pervasives.output_value`` や C言語による | ||
補助関数の実装などが必要である(Endianness に注意すること)。 | ||
|
||
|
||
``nativeint`` | ||
============================= | ||
|
||
``int`` は OS がサポートする基本整数型の幅から 1bit 少ない範囲の整数しか | ||
取ることが出きなかった。OS のシステムコールなどはフルに整数幅を使うことが多いため、 | ||
OCaml でシステムプログラミングを行う際には ``int`` では不便なことが多い。 | ||
(関連 OS 機能が整数の範囲としてフルサイズを使わないと確信できるときは ``int`` を | ||
使ってももちろん構わない。) | ||
|
||
``nativeint`` は OS の基本整数型と同じ幅を持つ符号付き整数型であり、 | ||
``int`` とは違い「失われた1bit」は無い。そのためシステムプログラミングに向いた整数型 | ||
といえる。一方、 ``int`` が 1bit を犠牲とすることで unbox化された表現を持ち | ||
高速な演算が可能であるのに対し、 ``nativeint`` はフルサイズで box化されたデータ表現となり、 | ||
GC の対象となるため、 ``nativeint`` の計算は ``int`` と比べるとメモリ領域を多く使用するし、遅くなってしまう。 | ||
|
||
CR jfuruse: どれぐらいおそいか | ||
|
||
定数の書式 | ||
---------------------------------- | ||
|
||
``nativeint`` の定数は整数の後に ``n`` をつける。すなはち:: | ||
|
||
# 1n;; | ||
- : nativeint = 1n | ||
# 0x1234n;; | ||
- : nativeint = 4660n | ||
(* 0oxxxn (8進), 0bxxxn (2進) も可能 *) | ||
|
||
``Printf`` 系フォーマット文字列では %nd %nx などやはり ``n`` を使う: | ||
|
||
# Printf.sprintf "%nd" 42n;; | ||
- : string = "42" | ||
# Printf.sprintf "%06nx" 123n;; | ||
- : string = "00007b" | ||
|
||
基本的な演算子 | ||
---------------------------- | ||
|
||
``nativeint`` の関数は Nativeint モジュールに定義されているが、 | ||
四則演算が ``add``, ``sub``, ``mul``, ``div`` と二項演算子ではなく | ||
普通の関数となっているなど、このままでは、不便である。 | ||
|
||
後述の ``int`` 以外の演算子でも普通の四則演算子を使う も参照のこと。 | ||
|
||
|
||
``int32`` と ``int64`` | ||
================================== | ||
|
||
``int32`` と ``int64`` は ``nativeint`` と同じく「失われた1bit」の | ||
無い、 box化された符号付き整数型だが、幅はアーキテクチャに関係なく | ||
``int32`` は 32bit、 ``int64`` は 64bit固定である。 | ||
|
||
|
||
定数の書式 | ||
---------------------------------- | ||
|
||
``int32`` は整数の後に ``l``, ``int64`` は後に ``oL`` と書く。 | ||
|
||
|
||
# 1l;; | ||
- : int32 = 1l | ||
# 0x1234L;; | ||
- : int64 = 4660L | ||
(* 0oxxxl (8進), 0bxxxL (2進) も可能 *) | ||
``Printf`` 系フォーマット文字列では %ld %Lx などやはり ``l`` や ``L`` を使う: | ||
|
||
# Printf.sprintf "%ld" 42l;; | ||
- : string = "42" | ||
# Printf.sprintf "%06Lx" 123L;; | ||
- : string = "00007b" | ||
|
||
基本的な演算子 | ||
---------------------------- | ||
|
||
``int32`` と ``int64`` のための関数はそれぞれ Int32 と Int64 モジュールに | ||
定義されている。四則演算が ``add``, ``sub``, ``mul``, ``div`` と二項演算子ではなく | ||
普通の関数となっているなど、このままでは、不便である。 | ||
|
||
後述の ``int`` 以外の演算子でも普通の四則演算子を使う も参照のこと。 | ||
|
||
|
||
``nat`` と ``big_int`` | ||
==================================== | ||
|
||
``Complex.t`` | ||
============================== | ||
|
||
OCaml の標準ライブラリには何故か複素数のためのモジュール ``Complex`` があり、 | ||
``Complex.t`` として複素数の型が定義されている。実装は非常に素直:: | ||
|
||
type t = { re: float; im: float } | ||
|
||
実数(``re``)と虚数(``im``)部分を ``float`` で表した二つ組。 | ||
この ``t`` に対して幾つかの基本的な | ||
演算が用意されている。が、文字列への変換も文字列からの変換も存在しない。 | ||
何のためにあるのかよくわからないモジュールである。 | ||
OCaml の標準ライブラリには、中の人が自分が便利だからと | ||
勢いだけで足してしまったこういうモジュールがいくつか有る。 | ||
中の人の特権…とでも言おうか。 | ||
|
||
``int`` 以外の演算子でも普通の四則演算子を使う | ||
================================================= | ||
|
||
|
||
符号なし整数: ocaml-uint | ||
================================================= |
Oops, something went wrong.