Soohの嘆き呟き

競プロ解説記事をかくぞ。

OCaml メモ

はじめに

関数論理型プログラミング実験というものがあり、OCamlを書くことになった。そこで、とりあえず色々メモしておいて、後で誰かの役に立てればええか〜と。大した内容は書かない(書きたくもない)ので、あんまり期待はしないでね。それでは、、、

 

文法編

・リストのコンス、連結について

コンス → A :: B

      x :: [y;z] (= [x;y;z]) だったり [a;b] :: c;d (= [[a;b];[c;d]]) として使う。

      同じ型のものを、より大きなリストに先頭に保存できる。

連結 → A @ B

      [x] @ [y] (= x :: [y]) だったり a;b @ c;d ( = [a;b] :: c;d) として使う。

      一重以上のリストで同じ型のものを、の数は増やさずに連結して保存。

 

(例) 二重配列 llst の各要素(リスト)の先頭にxを追加するやつ (画像すまん)

(注) llst = []の時なら動くが、とするとダメなのはお分かりだろうか

        []の時、y = , ys = (= 二重リストだけど空)であるからだ。

f:id:A_c_m_a_n:20210409161127p:plain

  • モジュールについて 

structure, signature, functorと3つ出てくる。

structure → C/C++でいうstructなどに結構似ているので問題ないと思う。

signature → そのモジュールが外部から見えてる型を表す。

signatureを使わないで 'a list' だけだと、ユーザ側が同じ型'a list' を持つ変数を宣言するなどして意図的にごっちゃにできるとよくない。

C/C++のstructでいうpublic, privateのイメージがあると理解しやすいかもしれない。

module M : signature = m

として宣言。実体は m と同等だけど、見えるものが異なる M が生成される。

OCamlのモジュール (ストラクチャ) とモジュール型 (シグネチャ) - Qiita

functor → 似たようなモジュールの定義を何度もするのを避ける目的。

module F = functor (T : TYPE) -> struct ... end

これはTYPEのシグネチャと同じ構造を持つものは、後でこのfunctor Fに代入することで、struct以後に書いた内容のものが実現できることを表している。

つまり、TYPEの部分を変えればmoduleの長い定義を1から書く必要がなくなる。

実際に代入するときは、module M = F (m) のようにmodule m を渡せば良い。

繰り返しになるが、この時の m は TYPEと同じ構造を持ってる必要がある。

signatureを返すようなfunctorもあるが、仕組みは同じ

OCaml 入門その4 モジュール・ファンクタ - Qiita

 

演算の優先順位について

6.7 式 をまずは見るべき。特に関数の優先順位は高いのと、左結合であることをしっかりと意識すると、変なバグや解釈をしなくて良い。特にfold_leftをfold_rightで書く課題などは、これ分かってないと詰むかも(私はList.fold_right で List.fold_left を書く - fetburner.coreを解読するのに、無限時間かけてしまいました...)。

 

コード編

再帰とかの挙動が分からない場合は、再帰の深さが小さいやつを手書きなどでもいいので展開してみるといい。

コードを書くとインタプリタ君がどんな型を想定しているかを返してくれるので、それを見るのもいいかもしれない。返り値はベースケースにしたやつの型になるので、わざわざみる必要もないかもしれないが...。どんな型の引数の想定になってるかとかの情報も見れるのは良さげ。

 

その他有名な事柄について(OCamlで書かれてないものも含む)

ラムダ計算、チャーチ数、再帰関数 :

すごいラムダ計算楽しく学ぼう - うさぎ小屋

lambda calculus - Does OCaml's type system prevent it from modeling Church numerals? - Stack Overflow

Lecture 29: Fixpoints and Recursion

多相、単相など:

Imperative Programming - Real World OCaml