いものやま。

雑多な知識の寄せ集め

pLucidをいじってみた。(その2)

前回はLucidの処理系であるpLucidについて紹介した。

今回はLucidについて触れていきたい。

Lucidとは?

Lucidというのは、前回も触れたとおり、データフロープログラミング言語の1つ。

データフロープログラミング - Wikipedia

Lucid (プログラミング言語) - Wikipedia

自分がこの言語に触れて一番変わってるなぁと思ったのは、変数が数列のように履歴を持つというところ。
なので、プログラミングが、漸化式を書くような感じになってたりする。
まぁ、これは実際の例を見てみないと分かりづらいと思うので、後で。

Hello, world!

とりあえず、新しいプログラミング言語に触れるなら、まずこれでしょ、ということで、Hello, world!から。

LucidでHello, world!を書くと、次のようになる:

`Hello, world!'

ちょっと注意が必要な点としては、最初のはクォートはバッククォートで、最後のはシングルクォートだということ。

これをpLucidで実行するには、まず適当なファイルに保存して(ここではhelloというファイルとする)、以下のようにコンパイル

$ lucomp hello

ただし、これはlucompから呼び出されるpass1、pass2、pass3、pass4、pass5が、PATHの通った適当な場所に置かれているのが前提。
もしこれらがPATHの通った場所に置かれていない場合、以下のようにして、パイプで処理をする:
(ここではpass1〜pass5がカレントにあると仮定)

$ ./pass1 hello | ./pass2 | ./pass3 | ./pass4 | ./pass5 hello

すると、hello.iという中間のバイナリファイルが生成される。

中間のバイナリファイルが生成されたら、次のように実行:

$ luval hello.i

さて、実行したらどうなるのかというと、こうなる:

$ luval hello.i
Evaluation begins .........

output(  0) : `Hello, world!' 
output(  1) : `Hello, world!' 
output(  2) : `Hello, world!' 
output(  3) : `Hello, world!' 
output(  4) : `Hello, world!' 
...(省略)...
output(995) : `Hello, world!' 
output(996) : `Hello, world!' 
output(997) : `Hello, world!' 
output(998) : `Hello, world!' 
output(999) : `Hello, world!'

$

なんじゃこりゃ!?、ってなるよねw

ただ、これがつまり、変数が数列のように履歴を持つということを意味している。

Lucidでは、一番外側にある式が評価され、その値が出力となる。
このHello, world!では、`Hello, world!'という文字列が式になっていて、その値が評価される。

だったら、`Hello, world!'が一回表示されて終わりなのでは?となりそうだけど、そうはならない。
というのも、これは、Lucid的には次のような意味になるから:

 {
output(n) = `Hello, world!' \quad (n = 0, 1, 2, \cdots )
}

そう、outputという変数は、単一の変数ではなくて、数列のように、0番目の値、1番目の値、2番目の値、・・・と、複数の値を含んでいるようになってる。
なので、pLucidはその値を順番に出力していった、と。
(実装的に上限が1000で固定になってるので、999番目の値で出力は止まってる)

うん、変な言語w

Hello, world!(真)

じゃあ、一回だけHello, world!を出力して終わりにしたかったら、どうするか。

数学的に考えれば、次のように場合分けすればいいことになる:

 {
output(n) = \left\{ \begin{array}{ll}
`Hello, world!' & (n = 0) \\
eod & (n \ge 1)
\end{array}
\right.
}

なお、eodは、データの終わりということ。

これをLucidで書くと、次のようになる:

`Hello, world!' fby eod

さっきと同じようにコンパイルして実行すると、以下のような出力になる:

$ ./luval hello.i 
Evaluation begins .........

output(  0) : `Hello, world!' 

Statistical Information about the evaluation
# of memory buckets created    =          0
# of space/time/place tags created   =          3

このとおり、1回だけ出力され、終了する。
(それ以外の出力もなんかいろいろ出てるけど・・・)

ここでポイントとなっているのは、fbyという演算子
これは"followed by"の略で、1回目は左項が評価され、2回目以降は右項が評価されるようになっている。
なので、output(0)は左項が評価されて`Hello, world!'になり、output(1)以降は右項が評価されてeodとなるので、データの終了ということでそこで出力が停止する、と。

ちなみに、fbyは右結合なので、次のように書くと、2つ出力して終わる感じになる:

`Hello, world!' fby `Good bye!' fby eod

実行例は、以下:

$ ./luval hello.i 
Evaluation begins .........

output(  0) : `Hello, world!' 
output(  1) : `Good bye!' 

Statistical Information about the evaluation
# of memory buckets created    =          0
# of space/time/place tags created   =          4

理屈としては分からなくもないけど、なんとも分かりにくい(^^;
アイディアは面白いと思うんだけど、もうちょっと分かりやすい記法はなかったものか・・・


なお、今自分がいじっているGitHubリポジトリは、luvalを実行するとセグメンテーションフォールトが発生するので、ここでの実行例は、おそらくGCCでオリジナルのコードをそのままビルドして作られたバイナリを使ってる。
自分のいじってる方も、そのうちちゃんと動くようにしたい。

今日はここまで!