ビスケットのあれこれ

ビジュアル言語ビスケット(Viscuit)に関するあれこれを書いてゆきます.

過去に発明した変な言語1

2012-05-20 09:28:18 | 1

これから,数回に分けて,僕が発明してきた変なプログラミング言語について書こうと思う.

このブログの読者層をちゃんと決めていなかったけれど,このシリーズに関してはなんかプログラミング言語を知っている人を対象に書く.書く目的は,プログラミング言語の幅の広さを理解しようというのと,ビスケットのルーツを探るという二点.


最初の言語は Laplas という言語.英語のつづりは Language Processor for listing and stacking という.このころは真面目にこういうのを考えていた(ちなみにViscuitにそういう英語のつづりはありません.BiscuitのBをVに変えただけです).あと,本当はLaplaceだよと教えてくれる人が続出したけど,そんなのは知ってます.

この動機は高専から北大に編入して,山本先生のところでLispを見せてもらって,あまりの面白さに感動して,でもカッコが嫌だから,カッコを使わないのを作ろうと思ったこと.もう一つは,高専の5年のときに3Dのタートルグラフィックを発明して,そのライブラリをPascalで書いていたのだけれど(これはトンボグラフィックといいます),これを簡単に呼び出せる言語が欲しかった.ちょうどタートルグラフィックに対するLogoみたいなやつ.

Logo はもろ英語を単純化した文法だったけど,そういうのがちょっと嫌で,日本語で読めるものというのもあった.

あと,Forthが好きだったので,そういう影響もあった.

というわけで「逆ポーランド記法によるリスト処理言語」というのです.ちなみに似たものにPostScriptがあるけれど,Laplasの方が2年か3年先です.まだMacが誕生する1年くらい前だもの.

こんな感じで動きます.

> 1 2 + ?
3

これは「1と2を足して表示」と読みます.最初の > はプロンプト.

プログラムは空白で区切られていて,それぞれの動作が決まっている.数字はその値をスタックに積む.+ はスタックに積まれている2つの数字を取り出して,足して,その答えをスタックに積む.? はスタックに積まれているデータを取り出して,表示する.

(1+2)*3という計算をするなら
> 1 2 + 3 * ?
9
となる.

リスト処理はこんな感じ

> (1 2 3) head ?
1
> (1 2 3) tail ?
(2 3)
> 1 (2 3) cons ?
(1 2 3)
> (1 2 3) snoc ? ?
(2 3)
1


カッコの始まりから終わりまでをリストといって,リストは一つのデータとしてスタックに積まれる(lispと違うのは,リストにクォートが要らないということ).最初の行は(1 2 3)というデータをスタックに積んで,headはスタックから取り出したリストの先頭をスタックに積んで,?で表示している.tailはスタックの先頭以外.consはスタックから2つのデータを取り出して,リストにしてスタックに積む.最後のsnocはheadとtailを同時にやる.

この言語をデザインするときに,気を使ったのがスタックの順序.snocとconsはちょうど逆の関係にあって,
> (1 2 3) snoc cons ?
(1 2 3)
となる.snocはhead,tailの順にスタックに積んで,consはその順でスタックから取り出す.

この順序がうまくはまったときはプログラムは気持ちがいいのだけれど,うまく行かないときは,スタック操作というのが必要になる.

> 1 2 ? ?
2
1
> 1 2 swap ? ?
1
2

このswapは,スタックに積まれている2つのデータを取り出して,入れ替えてスタックに積む,というのをやる.このほかに
> 1 dup ? ?
1
1
> 1 2 drop ?
1
> 1 2 3 rot ? ? ?
2
1
3

dupはスタックの先頭の複製,dropは1つ捨てる,rotは3つのデータを入れ替えるもの.rotまでくるとほんとわけがわからなくなるんで,めったに使われなかった.

Laplasでは関数を自分で定義できる.これが実に気持ちがいい.

> 'd (2 *) .
> 5 d ?
10

名前を実行せずにスタックに積む場合にクオート'が必要.最後のピリオド.が定義で,defunみたいなやつ.これでdという名前の中身は2 *である.これはdを2 *で置き換えたようにして実行する.

Laplasの中身は普通の仮想機械と同じで,プログラムポインタ(プログラムカウンタみたいなもの),制御スタック,データスタック,定義表,で構成されている.動作は非常にシンプルで,プログラムポインタはリストを指していて,そのリストのheadを実行して,ポインタはtailに進む.tailがnilなら,制御スタックから一つリストを取り出してプログラムポインタにセットする.実行するときは,+や?のような組み込み関数ならその内部定義を呼び出すし,ユーザ定義ならば,それをサブルーチン呼び出しする.

制御構造は

> 3 (2 *) 4 repeat ?
48

これは,repeatは数字とリストを取り出し,数字の回数だけリストを実行する.つまり

> 3 2 * 2 * 2 * 2 * ?
48

と同じ動きをする.条件分岐は

> 'check (0 = ("zero" ?) ("non zero" ?) if) .
> 0 check
"zero"
> (1 2 3) check
"non zero"

のように書く.真偽値はlispと同じでnilじゃなければ真.

あと,ローカル変数というのもあって

> 'append ((a b) var
:   a (a snoc b append cons) (b) if) .

とする.aとbにスタックの値が代入され,このスコープ内でaとbはその値をスタックに積むという定義になっている.

このappendの定義はaがnilでないなら,aをheadとtailに分解して(snoc),tail側とbとをappendして,その答えとaのheadをconsしている.aがnilならbを返す.consとsnocの使われ方が非常に美しい.

もう一つ特徴的な制御構造がmapsである.

>(1 2 3) (?) maps
1
2
3
>(1 2 3) (2 *) maps ? ? ?
6
4
2

リストを二つとり,最初のリストの各要素に対して,次のリストを実行する.スタックはそのまま.

それから[ と ]

> [ 1 2 3 ] ?
(1 2 3)
> [ 1 2 3 * ] ?
(1 6)

[はマークで,スタックに[そのものを積むだけ.]はスタックから取り出してリストを作ってゆく.[が来たら終わり.[と]は組み込みではなくてLaplas自身で定義することができる.ちょっと難しいけどやってみると,

> '[ ('[) .
> '] (nil ]sub) .
> ']sub ((h t) var h '[ = (t) (h t cons ]sub) if) .

(これは,いま脳内でデバッグしているから間違っているかもしれません)

この[ ]とmapsでlispのmapcarができる.

> [ (1 2 3) (2 *) maps ] ?
(2 4 6)
> [ (1 0 2 3 0) ((x) var x = 0 () (x) if) maps ] ?
(1 2 3)

2つめは,要素が0以外のリストを返している.ちなみに,これくらい簡単な式ならローカル変数を使わなくても,

> [ (1 0 2 3 0) (dup = 0 (drop) () if) maps ] ?
(1 2 3)

と書ける.

僕としては,maps と [ ] の発明が画期的だと思っているのだけれど,この面白さを共有できる人はあまりいないかも.リスト処理とスタック処理の相性の良さだと思うんだけど.

さて,このLaplasはリスト処理も面白かったけど,本当はトンボを飛ばすために作られた.たとえば,こんな感じ.

> 'star ((100 draw 144 turn) 5 repeat) .
> 'stars ((star 30 up) 12 repeat) .

stars は星を3次元的に回転させて12個描く.これは図が無いと説明しにくいな.まあ,こんな感じで遊んでた.

lispはプログラムとデータが同じ構造であるからプログラムの自動生成にいい,という説明があるが,Laplasも同じ特徴がある.Laplasの場合,関数と変数の区別もないので,lispよりもさらに簡単である.

このトンボグラフィックで,分子模型を作って遊んでいたのだが,こんな書き方ができる.

> tominit h h
> tominit h o h
> tominit h c h h h
> tominit h c h h c h h h

こんなんじゃわからないと思うけど,メタンとエタンを画面に表示する.Laplasのデータスタックとは別に,トンボ用のスタックが用意されている.tominitは最初に2匹のトンボを画面の中央に,ちょうど互いに反対向きになるように置く.hは今のトンボから線を引いて球を描いて消える.なので,最初の例は二つの水素がつながっているように描く.oは線を引いて球を描いて108度くらい角度を変えて,また線を引く.なので2行目は水の分子を描く.cは線を引いて球を描いて,3つの方向に3匹のトンボに分かれて(つまり自分の他に2匹増える)線を引く.このとき c や h はそれぞれstarのようなプログラムで描かれているのだけど,この書き方はプログラムと言うよりデータのように見えるではないか.制御構造を使って

> tominit h (c h h) 6 repeat h

のようにCが6個の(ヘキサンだっけ)分子も描けるので,制御構造付のデータとも見える.あとメチル基とかOHとか

> 'm (c h h h) .
> 'oh (o h) .

とか.

(うーむ.これは,ちゃんと復活させないとダメだね.)

PC-9801 の一番初期のはもちろんだけど,いろんなメーカーのCP/M-86に移植した.

いま思うと,テキストをちょっと入力して,3Dグラフィックを自由自在に扱う,というのはもっと注目されてもいいかもしれないな.あまりにもGUIに毒されすぎてしまった.

当時,この言語を説明する言葉を持っていなかったので,なかなか回りを説得できなかったのだけど,今だったらどういう説明ができるだろうか.仮想機械を直接触れる言語って感じになるかな.データとプログラムを自由に行き来するというか,自分が機械と同列になって機械と遊べるというか.

スタック言語はパイプラインの一般化でもあるんで,
今風のバリエーションも考えてみたら面白い.

たとえば,データをリストじゃなくてXMLにするとか,集合を導入するとか.


最新の画像もっと見る

コメントを投稿