type t (* void *)

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

OCamlのformat型の変な?型付け

ツイッターやらリアルで話しすぎてどこまで書いたかわからないけどformat型についてまとめておく。 言いたいことはほとんどこれだけ。

内部実装の解説

github.com

OCamlの上の部分を見ていくと、これは type_expect_関数の中で分岐している。この関数まさに式に型をつける途中のプログラムである。 これを見るとASTの構成要素によってパターンマッチをしている。

ty_expectedは文脈が要求している型のこと。 これは普通の意味で例えば let a = b + 1 in ...と書いてあればbにはintが要求されるだろう。 つまり、 文字列定数に対しての要求される型がformat6型のとき、それはformat6型を持つことができるということである。

プログラムの解説

その上で上の挙動をみていくと、

let s : (string -> string, unit, string) format = "Hello, &s" in Format.sprintf s "world" ;;

let s = "Hello %s!" in Format.printf s "world" ;;

上のプログラムではsはformat6であることを要求されるが、これの型付けには成功する。
なぜなら文字列定数が右辺にあり、これはformat6型を持つことが出来、その型がそのままsの型になるからだ。

下のプログラムでは、sstring型を持つ(なぜならformat型であることを要求されないから)。 in以降でsはformat6型であることを要求されるが、文字列定数ではないのでこのcoercionには失敗する。

まとめ

format型にcoercionできるのは文字列定数だけだよ。 一度string型がついた変数とかはもうcoercionできないよ。

おまけ

上の答えはバージョンに依る、です。4系からは現在の実装とほぼ同じ仕組みになったので型がつきます。 3.12とかを使っている人は型付けに失敗するよ。