type t (* void *)

関数型言語や英語学習の事とか。

OCaml: RWOを読み進めるためのOCaml設定

20150426加筆 RWOの説明を書いた
20150422加筆 より細かく書いた

20150909加筆 以下の内容はDebian 7向けに書かれており古いです! Debian 8ではより簡単にopamをインストール出来るようになっています! 下の記事では重複する部分は書きませんでしたが、インストール方法については下の記事が最新です。

no-maddojp.hatenablog.com

なんかちょっとだけOCaml環境構築が面倒みたいな話があったので、構築手順を書く。
大体確かめられた手順なのでよいはず。

Emacsのインストールまで解説しますが、RWOを読み始めるにあたりエディタの設定は必ずしも必要ではありません。
楽しんで下さい。

続きを読む

プログラミング: 今日の問題

プログラミングの問題。なんか全然綺麗にかけなかったので記事にする。

続きを読む

きつね: キツネ村にいくぞ!!!

keenさんと話していたやつ

https://www.amazon.co.jp/%E3%81%8D%E3%81%A4%E3%81%AD%E3%81%95%E3%82%93%E3%81%A7%E3%82%82%E3%82%8F%E3%81%8B%E3%82%8BLLVM-%E3%82%B3%E3%83%B3%E3%83%91%E3%82%A4%E3%83%A9%E3%82%92%E8%87%AA%E4%BD%9C%E3%81%99%E3%82%8B%E3%81%9F%E3%82%81%E3%81%AE%E3%82%AC%E3%82%A4%E3%83%89%E3%83%96%E3%83%83%E3%82%AF-%E6%9F%8F%E6%9C%A8-%E9%A4%85%E5%AD%90/dp/4844334158/ref=sr_1_1?ie=UTF8&qid=1518180267&sr=8-1&keywords=LLVM

  • 直近の知り合い2ホイップくらいで旅行にいきたいですねーーー
  • 3月にやります、知り合いっぽい人は声かけるので是非ご参加下さい
  • 東北大学工学部の最終講義もある(3/9、外山先生が退官される)

やること

  • 日程決め(3/9から2泊にするか)
  • インターネットがあって小会議室が予約できるホテル(蔵王の近くで)
  • 好きそうな知り合いに声をかける

C++: 返り値として自分自身を返すメソッドにshared_ptrを使う

#include <vector>
#include <memory>
#include <utility>

class A {
public:
    int x;
    A(int x) : x(x) {}

    std::shared_ptr<A> f() {
        return std::shared_ptr<A>(this);
    }
};

int main() {
    auto a = std::shared_ptr<A>(new A(123));
    auto v = std::vector<std::shared_ptr<A>>();
    v.push_back(a->f());
    v.push_back(a->f());
    return v.size();
}

*** Error in./a.out': free(): invalid pointer: 0x00007ffcc80eb1cc ***`という素敵なメッセージとともに異常終了する。

教えていただいた方法で試してみる。

#include <vector>
#include <memory>
#include <utility>

class A : public std::enable_shared_from_this<A> {
public:
    int x;
    A(int x) : x(x) {}

    std::shared_ptr<A> f() {
        return shared_from_this();
    }
};

int main() {
    auto a = std::make_shared<A>(A(123));
    auto v = std::vector<std::shared_ptr<A>>();

    v.push_back(a->f());
    v.push_back(a->f());
    return v.size();
}

これは正常に終了する。めでたしめでたし。 ただしこれ、必ずthisがshared_ptrにより管理されていなければならず、そうでない場合にはエラーが発生するっぽいのでなかなかこわい。 例えば上の例ならばmainの中にauto b = new A(256); b->f();という行があったならば、

terminate called after throwing an instance of 'std::bad_weak_ptr'
what():  bad_weak_ptr

といってしんでしまう。

OCaml: 型変数の雑い話

これはMLアドベントカレンダーの1日目の記事です。 今年で3年目のアドベントカレンダーですが、あまり埋めるということは意識せず、MLユーザが記事を書いてワイワイするという目的でやっていければいいな、という感じです。

adventar.org

1日目なのでゆるくOCamlコンパイラの型周りの実装の話をしたいと思います。 最近あまり体調が良くなく、小ネタみたいな形です(すみません)。 どこかで喋った覚えもあるので聞いたことがある人がいたらすみません。


OCamlでは型変数は基本的に整数のidで表されています。 それにレベルという概念を導入して、どのネストのletで導入された型変数なのかをわかるようにしている、というのは以前書いたとおりです。

github.com

また型変数がgeneralizeされているかどうを表すためにも利用されていて、Btype.generic_level = 100000000と定義されています。まぁ常識的にこの深さのネストとかやらんやろということで再利用しているんだと思います。

気になるのは、型変数をidという形で整数で表してしまうと、idが衝突するのではないのかということです。例えばcmiファイルからロードする際に他のファイルから型をインポートするときに混じったりということが考えられます。

この手の情報は手軽に見ることができます。compiler-libsさまさまです。 utopかなにかで読み込んで、プリティープリントさせてみましょう。

// 前やったときはできたと思うんですが、なんか今はできませんでした。 // utopまわりで色々変わったのかもしれません、すみません

utop[0]> #require "compiler-libs";;
utop[1]> read_cmi

これを見ると、cmiの世界の中では型変数のidはマイナスの数になっていることがわかります。 これを自分たちの、いまコンパイルしようとしている世界にむけてidを差し替えます。それには型とかモジュールを表すデータ構造をあれそれ置き換えるためのモジュールSubstを利用します。

Subst.typexp: Subst.t -> Types.type_expr -> Types.type_exprは型を表すデータ構造をトラバースして、型変数を見つけたら置き換える関数です.

(* Similar to [Ctype.nondep_type_rec]. *)
let rec typexp s ty =
  let ty = repr ty in
  match ty.desc with
    Tvar _ | Tunivar _ as desc ->
      if s.for_saving || ty.id < 0 then
        let ty' =
          if s.for_saving then newpersty (norm desc)
          else newty2 ty.level desc
        in
        save_desc ty desc; ty.desc <- Tsubst ty'; ty'
      else ty
......

idが負であれば何やら怪しい方法でコピーしています。 for_savingは普通の場合ではfalseです。 ちなみにこのfor_savingというのはこの逆で、型変数のidを外に書き出したりするときにtrueになる変数です。newperstyidを負になるように置き換えます。

上のようなことが起きるのは、下の関数の中身くらいでです。

read_signature
  read_pers_struct
    acknowledge_pers_struct
      components_of_module'

ちなみにOcamlコンパイラの中身ではモジュールの並び順的にあとのモジュールに入っている関数を利用するために関数のrefみたいなものをたくさん作っており、'がつくものはその印です。

読んでみた感想なのですが、OCamlの型検査周りの実装というのは本当に複雑で、色々手に終えないです。型付けのためのデータ構造が効率のため一時的にしか現れないはずもの(Tlink, Tsubstなど)、といったものなどもありかなり複雑で、やはり関数型言語で書けば可読性が上がるなどといった話は嘘なんだなと強く確信がもてます(この手の話では関数型言語Haskell、それもGHCしか指さないという話もありますが)。 気づいたらocaml/typingの中に素敵なことにHACKING.adocというファイルができていました。

https://github.com/ocaml/ocaml/blob/trunk/typing/HACKING.adoc

これは本当に素晴らしいことで、突然開発者が交通事故にあっても大丈夫なようにOSSといえども実装をドキュメントとして残していく必要があります。 ソースコードに全て書いてあるなどと言うのは開発者の怠慢で後で読む人に一生懸命考古学させる、ドキュメントを書きましょう。。。

最後に今年の振り返りですが、今年のOCaml活動はコンパイラの同人誌をOCamlで書いたこと・ML勉強会を一応開催できたことは良かったです。 あまり最近OCamlをかけていないのですが、来年度はドンドンやっていきたいと思います!

nomaddo.booth.pm ml-lang.connpass.com

次はポケバさん@pocketberserkerさんです。

一般の話: 技術書典3で追記部分

技術書典3お疲れ様でした!
取り急ぎ、今回入稿した文の修正分についてお知らせします。

今回入稿したデータが間違っていたのか、印刷所が間違えたのか、私の追記部分が抜けて落ちております。 そのため最適化の部分だけPDFをアップロードしますので是非御覧ください。
電子書籍版では既にアップロード済みです。

nomaddo.booth.pm

www.dropbox.com

一般の話: 転職します

実は8月の頭が最終出社日で、8月で今の会社を退社します。
今週から東京に引っ越しています。
東京の北の方に御用の際はぜひお立ち寄りください。

今の会社では開発環境整備とか、製品の開発を行っていました。 色々苦労してcvsからgitにした話は名古屋のLTで話した感じです。 色々あって山奥もきつくなってきたのと、誘われた話が面白そうだったので転職することにしました。

次は9月からidein.jpにジョインします。
今いる人達はすごいエンジニアばかりですが、 コンパイラマンとしていい仕事が出来るように頑張ります。