Skip to content

Commit

Permalink
added old files
Browse files Browse the repository at this point in the history
  • Loading branch information
Jun FURUSE committed May 27, 2016
1 parent 9c5e571 commit afdedf6
Show file tree
Hide file tree
Showing 37 changed files with 8,149 additions and 0 deletions.
426 changes: 426 additions & 0 deletions bb/4.02.md

Large diffs are not rendered by default.

16 changes: 16 additions & 0 deletions bb/README.md
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` というファイルを読めとは書きますが、その中の一歩一歩を辿ることは
しません。なぜならそれは元の情報を劣化させて不正確にしたものを伝えること
だからです。
19 changes: 19 additions & 0 deletions bb/caml_bool.rst
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"
269 changes: 269 additions & 0 deletions bb/caml_num.rst
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
=================================================
Loading

0 comments on commit afdedf6

Please sign in to comment.