2007/05/19

Erlang クエックブックにインデックスを付ける

Erlang クエックブック にインデックスを付けました。
手でつけるのはめんどうだったので、Erlang でインデックスを付けるようにしました。
そのソースです。P とか R だったらもっと簡単にできる、というのはここではなしで。
if も case もなしで。
さらに、”クエック”って何よ、というのもなしで。


#!/usr/bin/env escript

main(_) ->
{ok, In} = file:read_file("cookbook_src.html"),
{Index, Contents} = f(binary_to_list(In), [], []),
Dest = insert_index(Index, Contents),
file:write_file("cookbook.html", Dest).

insert_index(Index, Contents) ->
P = find_index(Contents, 0),
{X, Y} = lists:split(P, Contents),
X ++ Index ++ (Y -- "*index_place*").

find_index("*index_place*" ++ _, N) ->
N;
find_index([_|C], N) ->
find_index(C, N+1).

f([], Index, Contents) ->
{lists:reverse(Index), lists:reverse(Contents)};
f("<h2>" ++ T, I, C) ->
[Ast|Ref] = erlang:ref_to_list(make_ref()),
I2 = io_lib:format("<h3><a href='~s'>", [[Ast|Ref]]),
H2 = io_lib:format("<h2><a name='~s'>", [Ref]),
h2(T, [I2|I], [H2|C]);
f("<h3>" ++ T, I, C) ->
[Ast|Ref] = erlang:ref_to_list(make_ref()),
I3 = io_lib:format("<a href='~s'>", [[Ast|Ref]]),
H3 = io_lib:format("<h3><a name='~s'>", [Ref]),
h3(T, [I3|I], [H3|C]);
f([X|T], I, C) ->
f(T, I, [X|C]).

h2("</h2>" ++ T, I, C) ->
f(T, ["</a></h3>"|I], ["</a></h2>"|C]);
h2([X|T], I, C) ->
h2(T, [X|I], [X|C]).

h3("</h3>" ++ T, I, C) ->
f(T, ["</a><br>"|I], ["</a></h3>"|C]);
h3([X|T], I, C) ->
h3(T, [X|I], [X|C]).

2007/05/16

Erlang Windows での ~/.erlang

Windows での ~/.erlang は %HOME% ではなく %HOMEDRIVE%%HOMEPATH% から読みとるらしい。

2007/05/15

Emacs の indent-tabs-mode はバッファローカル

Emacs の indent-tabs-mode はバッファローカルなんですね。
グローバルに値を変えたい場合は setq ではなく setq-default を使かいます。


(setq-default indent-tabs-mode nil) ;タブではなくスペースを使う。

2007/05/14

perl - telnetコマンドを自作する の Erlang バージョン

perl - telnetコマンドを自作する の Erlang(escript)バージョンです。


#!/usr/bin/env escript

main([Host]) ->
main([Host, telnet]);
main([Host, Port]) when is_list(Port) ->
main([Host,
case catch list_to_integer(Port) of
{'EXIT', _} ->
list_to_atom(Port);
Num ->
Num
end]);
main([Host, Port]) when is_atom(Port) ->
{ok, Num} = inet:getservbyname(Port, tcp),
main([Host, Num]);
main([Host, Port]) ->
{ok, S} = gen_tcp:connect(Host, Port, []),
spawn_link(fun() -> send_loop(S) end),
recv_loop(S).

send_loop(S) ->
Line = io:get_line(''),
gen_tcp:send(S, Line),
send_loop(S).

recv_loop(S) ->
receive
{tcp, _Port, Data} ->
io:format(Data);
{tcp_closed, _Port} ->
exit(normal)
end,
recv_loop(S).

2007/05/13

Erlang standard_io は group_leader()。あるいは、file:read/2 で標準入力からリードする方法。

Erlang の io モジュールで明示的に標準入出力を指定する場合は standard_io を指定するとなっています。
その standard_io って何でしょう。
io モジュールのソースを見ると IoDevice を省略、または stadard_io を指定すると、group_leader() を IoDevice に指定するようになっています。
group_leader() は erlang モジュールで定義されています。
Erlang の全プロセスはいずれかのプロセスグループのメンバーとなっています。
erlang:group_leader/0 はそのプロセスグループのリーダーを返します。
グループ内の IO 処理はそのグループリーダーを通して行われます。
すなわち、Erlang の各プロセスにとって標準入出力とはグループリーダーそのものなのです。
というわけで、標準入出力を使用する時に group_leader() 呼んでいるのです。

以上が、前置きです。
本題は file:read/2 で標準入出力からリードする方法です。
file:read/2 に standard_io を渡しても {error,einval} が返ってきます。
上記をふまえ、ここでは group_leader() の返り値を渡せばいいのです。


1> file:read(standard_io, 1).
{error,einval}
2> file:read(group_leader(), 1).
a
{ok,"a"}


ちなみに、Common Lisp の標準入出力は *standard-input* と *standard-output* ですね。

2007/05/12

Erlang で if って

使わないよね。case は使うけど、if は本当に使いません。
以下、とりとめのない文章ですが。。。
普段の仕事で(Erlang ではない)if → 条件分岐 → テストケース増 という図式があるので、if がないプログラムはとても好ましいのです。
case も条件分岐なので if と変わりないかもしれませんが、case は条件分岐というよりむしろパターンマッチング感が強いので、心理的抵抗が低いのです。
case も関数呼び出しのパターンマッチングに置き換えられるので使わないで済ませられます。
Common Lisp でも if より and や or の方が気持ちがいいです。
単に if 嫌いなのかもしれません。
というわけで、if 嫌いなあなたに Erlang を。

Windows への TeX のインストール

Windows に TeX をインストールする際のメモです.

まず、あべのり[阿部紀行]さん作成のTeXインストーラ3を使います。
http://www.ms.u-tokyo.ac.jp/~abenori/mycreate/index.html から TeXインストーラ3 0.58 kakuto3_0_58.zip をダウンロードします。
ダウンロードした kakuto3_0_58.zip を解凍して kakuto3\kakuto3.exe を実行します。
インストール先は C:\home\ancient\local\opt\tex を指定。
他は何もかえずに「次へ」ボタンを数回押すと, ファイルのダウンロードとインストールが開始します。
AFPL Ghostscript Setup のダイアログでは Install to directory を c:\home\ancient\local\opt\gs\gs に, Use Windows True Type fonts for Chinese, Japanese and Korean を チェックします。
GSView は全てデフォルトのままでインストール。
うながされるまま再起動します。

次に WinShell をインストールします。
http://www.winshell.de/ から WinShell31.exe をダウンロードして実行します。
インストールが完了したら、WinShell が起動するので、Choose Language で Japanese を選択しましょう。

WinShell の設定を行います。UTF-8 を使用する設定にします。
メニューの「オプション」「全般」をクリックします。
「一般」タブで、言語に Japanese、ファイル形式に Unix を指定します。
「主なTeXプログラムの設定」タブで、
LaTeX: platex、コマンドライン: --kanji=utf8 -src-specials -interaction=nonstopmode "%s.tex"
BibTeX: jbibtex
DVI -> PS: dvipsk
PDFLaTeX: dvipdfmx、コマンドライン: "%s.dvi"
「ユーザ指定プログラム」のタブで、
Tool1: mendex、exeファイル名: mendex、コマンドライン: "%s.idx"
「フォント」タブで、「文章」のフォントを「MS ゴシック」、スクリプトを「日本語」、エンコーディングを「UTF-8」
というように設定します。

dvipdfmx で otf が使えるように設定します。
c:/home/ancient/local/opt/tex/share/texmf/dvipdfm/config/dvipdfmx.cfg の末尾に
f cid-x-local.map
を追記します。
c:/home/ancient/local/opt/tex/share/texmf-local/fonts/map/dvipdfm/local/cid-x-local.map を http://oku.edu.mie-u.ac.jp/~okumura/texwiki/?OTF#z044b3e2 の For dvipdfmx の フォントを埋め込まない場合 にあるとおり内容で作成します。
最後に mktexlsr.exe を実行します。

dviout もいい加減な設定をしておきます。
WinJFont で hminr-h を MS 明朝、hgothr-h を MS ゴシック で Define して Save します。