Skip to content

Latest commit

 

History

History
145 lines (101 loc) · 7.1 KB

langspec.md

File metadata and controls

145 lines (101 loc) · 7.1 KB

言語仕様

List の ; と tuple の ,

List, Array, Record などの要素区切りの ; はとても奇妙に見えるかもしれない。 OCaml を使っている人でもあまり意識していないのだが、実は一貫性がある。

  • A ; BB ; A と書いても型は変わらない
  • A , BB , A と書くと型が変わる場合がある

例:

  • print_string "hello"; print_string "world"
  • { a = 42; b = "hello" }
  • [ 1; 2; 3 ]
  • [| 1; 2; 3 |]

これらの要素を入れ替えても型は変わらない。もちろん意味は変わる場合がある。

例:

  • (1, "hello")
  • (int, float) Hashtbl.t

これらの要素を入れ替えると型が変わってしまう。

なんで OCaml には Haskell の様な関数型マリオ機能がないのか

OCaml はその昔から関数型言語のくせに関数合成の記号すらない。(|>)(@@) が入ったのも つい最近である。なぜ、無いのか。

これは明文化されていないが、この言語と長く付き合うとだいたい判る。 OCaml は関数型配管工的なものはできるだけ提供しない、という思想が根底にあるとしか思えない。

何故便利な配管記号がないのか、何故自由に演算子の結合則を変えられないのか… なぜなら、それを許すとプログラムが読みにくくなるから、と中の人が考えているからだ、と思われる。 アルファベットで書かれた普通の関数は命名がしっかりしていれば、大抵意味はわかるし、 Googleability も高い。逆に読み方の判らない記号はそれが何を意味しているのか 調べるのはなかなか難しい。 OCaml はその先代の Caml-light の時代から教育で使われてきたこともあり、難しい記号はできるだけ 避けるようになったものと推測する。

Haskell がとっつきにくさの理由の一つに記号が難しすぎる、事を挙げても誰も否定できないだろう。 もちろん配管工記号があれば便利だし、それを使えばプログラムは短く読みやすくなる(こともある)。 ただしそれはその記号に慣れている人だけだ。OCaml はそれを気にして記号は数値演算以外は ほとんど使わないことにした。もちろん配管工記号がなければプログラムは長くなる、 が、それは別にいいじゃないか馬鹿っぽくても誰でも読めるのならば。 これは記号を組み合わせる関数型ギミックの好きな人には耐え難いことかもしれないが OCaml の根底思想なので、嫌なら OCaml の制限上で上手く演算子をやりくりするか、別言語をやるしか無い。

もちろん OCaml でプログラムを書いている人間も Haskell を触ったり F# を触ったりしていると 配管工記号が欲しくなってくる。周りからせっつかれて、最近ようやく (|>)(@@) が 入ったのはそういう事情による。

Haskell や F# のように記号を使いたい

どうぞご随意に、自分で定義できますよね?私らは用意しません。 というのが OCaml スタイル。

ただし、OCaml では記号の結合方向や強さは主にその位置文字目の記号によって固定されており、 変更することができない。 これを使えない、と見るか、 妙な結合方向や強さを持つ記号を大量生産されないようにしているか (どこかに記載されている結合方向と強さを調べないと 人間が理解以前にパースさえできないコードってどうなんですかね?)、 と見るか、だが、兎に角現実として固定されいているのでまず それを列挙しておこう。

下にいくほど強くなる

  • right :=
  • right ||
  • right &&&
  • left =, <, >, |, &, $ で始まるものと !=
  • right @^ で始まるもの
  • right ::
  • left +- で始まるもの
  • left ** を除く *, /, % で始まるもの
  • right **
  • prefix !=, ~, ? を除く !, ~, ? で始まるもの

もし記号をふんだんに使った他人には判りにくいライブラリを作りたければ、 この表を良く良く見て、結合方向と強さにあった記号を選んで 少なくともあなた自身には便利なものを作らなければいけない。 幾つかよく使われる物を挙げておく:

Monadic bind >>=

Monadic bind >>= はそのまま使えば良い。 Jane Street では >>| を fmap として使っている。

Pipe |>

F# の |> はそのまま使えば良い。標準で使えるようになっている:

external (|>) : 'a -> ('a -> 'b) -> 'b = "%revapply"

Haskell's $

Haskell の $ は右結合で結合力は最も弱い0。 OCaml では $ は左結合なので使えない。 これは右結合 & をお薦めする。Logical AND は logical OR が || なため、皆 && を使い、& は使わないので使ってしまって良い。|> と同じくパフォーマンスのために "%apply" を使う:

external (&) : ('a -> 'b) -> 'a -> 'b = "%apply"

残念ながら |>& より強いので f & g x |> hf & (g x |> h) とパースされてしまう。 見た目的には |> の方が分断感あるので (f & g x) |> h となって欲しいところ。

OCaml 4.01.0 から @@%apply として採用された…のだが私は嫌いである。二文字だし、結合力が強過ぎる。

Functional composition

関数合成 (Haskell の .) は右結合でかなり強くなければいけない。 ** を 使うのが良いと思う。当然、数値計算の ** と合成の ** を同時に使うことはできないので そこは場合によってよく使う方を選ぶことになる。私は数値の ** はほとんど使わないので let power = ( ** ) としている。

このところ ( *< ) がいいかなあと思っている。 (f *< g) x = f (g x) その逆は (f *> g) x = g (f x) 。どうだろう。

Others

ITPL の人は !%Printf.sprintf に使っている。 % は format 文の意か。私もこれを採用した。 Format.eprintf!!% にした。

Variant constructor を curry 化したい

できない。 fun x -> Some x のように手で書くこと。

なぜ OCaml のコンストラクタ(variant constructor)は partial application できないのか https://groups.google.com/forum/?fromgroups=#!topic/fa.caml/IOlkCcVBg5Q

typpx パッケージに付属する ppx_curried_constr を使うと割と自然にコンストラクタを 関数化できる。

コンストラクタその物ではないが同名の関数(たとえば Some コンストラクタなら some という関数)を定義を自動生成する ppx_variants_conv パッケージというのもある。