アセンブラが一番簡単だと思うんだ。
* 基本、上から一つずつ実行
あとはジャンプとコールだけだし。
次は、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:
Post a Comment