Sunday, 24 June 2012

実行の読めないプログラミング言語

アセンブラが一番簡単だと思うんだ。

* 基本、上から一つずつ実行

あとはジャンプとコールだけだし。

次は、C とか Pascal だよね。LISP や ML 、Ocaml あたりも、この範囲。別にどうってことない。上から下、右から左、中側が先に実行される。C みたいに引数の評価順が決まってないとかは、やめて欲しいが。

オブジェクト指向言語だと、間接ジャンプの塊みたいなものなので、次にどこが実行されるかがわからない。特に、ステートパターンを使うと、さっぱりわからなくなる。C でも、間接呼び出しを多用するとそうなるね。

まぁ、でも、こんなのは可愛い方で、

* Prolog の backtrack がどこに飛ぶか

これは難しい。一番最近の Choice Point だってのはわかるが、それを読み切らないとプログラミングできない。

* ?-append(X,Y,[a,b,c]).

が、どう動くか読めるようになったら一人前か?

C++ のtemplate は見かけのごまかしで「実行を読めなくする悪い意図」のためにだけあるという感じ。Java の generic は、そこに余計な呼び出しを追加されるようなことはないのだが、Method override を使われると読めない。

* VHDL, Verilog

これらは、まぁ、クロックがあるので、割とやさしい。全部、一度に動いていると思えば良いんだろ?

でも、まだ、この辺りは正気な部類だと思う。

* Concurrent Prolog

Commited Choice 言語とか呼ばれるもの。

Concurrent Prolog (LMNtal とか) はデータ駆動的に動くので、代入(と言わずに instaciation というのだが) によって、複数の呼び出しが並列に動く。慣れればどうってことない説はあるが、魔術的。書いてある順序になんか動かない。論理変数を共有しているすべての goal を把握しておく必要がある。字面とは関係なく、それが把握できれば問題ない。

SPIN の Promela は同じ問題を抱えているが、channel が明示的。Thread でも似たような問題はあるが、wait が明示的なのが救いか? Concurrent Prolog は、その辺りが、まったく見えないからなぁ。

* Haskell

遅延評価とかいう人もいるけど、合流性があるから、関数パターンがマッチして展開(reduce)できるものは、いつ評価しても良い。ということは、

* 原理的に実行が読めないはずの言語

ってことね。実際、step trace してみると、極めて予想外の動きをしていることがわかる。だいたい、outer most で実行しているはずなので、引数は関数呼び出し時に評価されないのが普通。

let rev3 x y = if x==[] then y else rev3 (tail x) ((head x) : y)

とかでも、かなり謎な動きをします。たぶん、実行順序とか気にしたら負けな言語。

[append1.hs:12:23-34] *Main> :step
[Stopped at append1.hs:12:24-29
_result :: a = _
x :: [a] = [_]
[append1.hs:12:24-29] *Main> :step
3Stopped at append1.hs:12:23-34
_result :: [Integer] = _
x :: [Integer] = [_,3]
y :: [Integer] = _

これは、最後に表示しようとしてから、どっかが実行されているんだろうなぁ。

この手の正気でない言語も結構好きだな。

No comments: