読者です 読者をやめる 読者になる 読者になる

OCamlのインタプリタで日本語の文字を扱う

あれはおそらく2013年、Perl入学式に初めて参加する直前頃だったと思うのだけど、以下の本を購入し、

プログラミングの基礎 (Computer Science Library)

プログラミングの基礎 (Computer Science Library)

そこに示されるまま、OCamlインタプリタで日本語を出力するためにターミナルの文字コードEUCに設定したら、その後に行ったPerl入学式で出力が文字化けしてしまい、「どうしてですかね……?」と聞いたら「端末の設定が問題なんじゃないかな!?」とサポーターさんから指摘され*1、「ああ、あのOCamlの設定でやったやつか……」と、おかげで少なからぬ時間を費やしてしまったことがあまりよくない印象として残ってしまい、その後同書を開くことはほとんどなかった。

しかし最近、以下の記事を読んで、

これといった目的もなくプログラミングを始めたいなら、静的型付き言語で始めるほうがいろいろ実りがあると思います。

とのこと。

なるほど、そういえばOCamlの本、以前買ったのがあったな、ちょっと読み直してみよう。と思って、その後なんだかんだで3年間趣味プログラミングを続けてきた今の目で読んでみると、読みやすいし、面白そうだし、期待できそう。
さすが様々な機会で良書として推薦されるだけのことはある。

……しかし、件の文字コード問題がなあ、と思ってその部分をやってみると、やはり普段使っているUTF-8の設定だと文字化けする。指示のとおり端末の方でEUCに設定してしまうことも可能だけど、他のコードを扱うときのことを考えると受け入れがたい。

インタプリタにこだわらず、ファイルにコードを保存して実行すれば問題ないのだけど、同書の構成としては前半しばらくの間はインタプリタ操作を前提に進んでいくので、できればそれに沿って読み進めたい……などとジレンマ的な状況に陥りつつ、しかしこんなメジャーな(と言っていいだろう)言語でこんなしょうもないことが放置されているはずがない、と思っていろいろ検索してみたら、ようやくわかった。端末を直接設定する以外の方法で、比較的手軽に文字化けを回避する方法が。

Toplevel (REPL) での文字化けを防ぐ

内部的には壊れているわけではない EUCUTF-8 の文字列ですが、出力が狂ってしまうのは不便です。 これは OCaml の string プリンタを変更することで回避することができます:

EUC もしくは UTF-8 環境:
# let print_non_escaped_string ppf = Format.fprintf ppf "\"%s\"";;
val print_non_escaped_string : Format.formatter -> string -> unit = <fun>
# #install_printer print_non_escaped_string;;
# "こんにちは";;
- : string = "こんにちは"

ここでは 文字列をエスケープせずに標準出力に出力する関数、 print_non_escaped_string を定義し、 それを #install_printer ディレクティヴによって string 型のプリンタに指定しています。 これにより文字列を ISO-8859-1 とみなしたエスケープが行なわれなくなります。

Toplevel で日本語を含んだ文字列などを多用する場合は、毎回この内容を打ち込むのをさけるために、 次の内容を OCaml toplevel が起動時に実行するファイルである .ocamlinit に 書き込んでおくとよいでしょう:

let print_non_escaped_string ppf = Format.fprintf ppf "\"%s\"";;
#install_printer print_non_escaped_string;;

ということで、最後に示されている2行を .vimrcや.bashrc と同様に、.ocamlinitとしてホームディレクトリに置いたら、インタプリタでも日本語が普通に出力されるようになった。

OCamlに関する日本語で書かれた情報じたいはけっして少なくないのだけど、本件についてはけっこう限られていて、なかなか大変だった。
そのような中、上記のリポジトリのほか、以下でも同様の言及があり、参考になりました。ありがとうございます。

*1:おぼろげな記憶だけど、それはたしかYAPC::Asiaのイベント内で開催されたPerl入学式で、このときに相手をしてくれたのはウズラさんだった気がする。