Más contenido relacionado
La actualidad más candente (8)
Similar a Robot Language and a Tail Recursive Interpreter (20)
Robot Language and a Tail Recursive Interpreter
- 1. 1
Robot言語
と
末尾再帰インタープリタ
2014/OCT/18
たけおか@AXE
twitter: @takeoka
www.takeoka.org/~take/
- 3. 3
Robot言語とは
● 再帰的な曲線を描くための言語
● 貧弱だが、ピュア関数型言語といえる
● タートル・グラフィックスで画を描く
● 非常に単純なプログラミング言語
● 繰り返し回数を記憶するために、Accが一つだけある
● オリジナルのRobot仕様書 & 実装
Litchen Wang:
An Interactive programming Language for control
of robots, DDJ, Vol.2, Issue 10, pp.60-63
(1977).
● 日本での紹介文書
石田晴久: ロボット言語, bit,Vol10, No.7, pp.35-
50(1978))
● たけおかのページ
http://www.takeoka.org/~take/kvm/robj.html
- 4. 4
組み込み関数など
● +
● 1+ Accをインクリメント
● -
● 1- Accをデクリメント
● h
● Home 画面中央部に移動
● n
● North 画面上方を向く
● c
● Clear 画面を消去
● r
● Rotate 45度右へ回る
● f
● Forward 線を引きながら1step進む
● j
● Jump 線を引かずに1step進む
● t(<非ゼロ文>)(<ゼロ文>)
● Test Accが0でないなら<非ゼロ文>のみを
● Accが0なら<ゼロ文>のみを実行する
● dF(<定義文>)
● defun ユーザ関数Fを<定義文>として定義する
● a
● Acc項になってAccの値を示す
● このRobotにはAccが一つだけある
● (0-2^31の値を取る)
● ユーザ関数
● 英小文字かつ予約されていない一
文字がユーザ関数名として使える。
● dでdefineする
- 5. 5
実行例
● ヒルベルト曲線
du(t(-vfxuyfufxv+)(x))
dv(t(-uyfvfxvyfu+)(y))
dx(6r)
dy(2r)
chna-5+2ru
● 無限ループ
db(z)
dz(frb)
- 6. 6
実行例
● ドラゴン曲線
dx(t(-x6rk+)(f))
dk(t(-x2rk+)(f))
chna-10+x
● シェルピンスキー曲線
dx(t(-xfxufuxfx+)(v))
du(5r)
dv(2r)
dy(6r3r4(fx))
chna-2+y
- 8. 末尾再帰呼出し→ループ 変換(コンパイル時)
8
● 自分自身の再帰呼出しは、容易に、ループに変換可能
● 再帰呼び出し recursive call
int
fact_tail_rec(int n, int a)
{
if(n == 1){ return a; }
else
return fact_tail_rec(n-1, a*n);
}
● ループ
int
fact_loop(int n, int a)
{
for(;;){
if(n==1) return a;
a= a * n;
n= n-1;
}
}
- 9. 9
コンパイラって楽だよね
● コンパイル時間が長くても、怒られない
● コンパイル時に、めちゃくちゃメモリを喰っても怒られない
● 程度問題はあるが…
● 広域を見れる
● (自己)末尾再帰を見つけるのも、関数のアタマからお尻ま
でゆっくりと見れる
● 実行時間が速ければそれで良し
● 組込みだと、メモリ・フットプリントも重要だが
– コード・サイズ
– ワーキング・メモリ(RAM)
- 10. 10
インタープリタは大変
● インタープリタの性能 = 実行時間
● JIT なんていうものも大事か…
● でも、JIT やるなら、実行前に機械語に変換しろよ
– 大方の言語なら可能だ
– Javaとか、わざと複雑にしてるよな
– 古いx86の自己書き換えコードなんか動かなくてもいい
よ(フツーの場合)
- 12. 12
末尾再帰インタープリタ
● 末尾再帰の最適化を見つけるためのものじゃないよ
● インタープリタの構造が、末尾再帰
● Continuation Passing 的なことを、インタープリタ内部で、
インタープリタ自身がやっている
↓
● インタープリタが、不要なスタックを消費しない
● テイル・リカーシブ・インタープリタ : インタープリタの実現方法
● 実行時に、実行のために明らかに不要な情報を記憶しない。
● 当然のようであるが、素朴な古い実装では、なかなか難し
い。
● テイル・リカーシブな実現のインタープリタで有名な言語
は、Schemeである。
- 13. 13
本インタープリタの実現int
exeq() // 1命令を実行する
{
n= term();
switch((ccc=CT[Pc++])){
case 'f' :
x1=x + n*v*step; y1=y + n*u*step;
drawLine(x,y, x1,y1, 0);
x=x1; y=y1;
break;
case '0' : /* func end */
{ Context *c;
c=stk_pop(); Pc=c->pc; CT=c->ct; top= c->top; n= c->n-1;
if(Pc== -1){ contAble=false;finishIt(); return; // 評価、全終了}
if(n>0){ /* n回 繰り返し中 */
c->n=n;
stk_push(c);
CT=top; Pc=0; //再度、関数の先頭
return;
}
return;
}
:
- 14. 14
本インタープリタの実現
:
default: /* ユーザ定義関数 */
top= defun[ccc-'a'];
/* 末尾再帰 最適化可能な時は、pushしない
ユーザ関数定義の末尾、すなわち、後に実行すべきものが何もない */
if(n!=1 || CT[Pc]!='0'){
Context c;
c.n=n; c.top=top; c.pc=Pc; c.ct=CT;
stk_push(&c);
}
CT= top; Pc=0;
//printf(" userFunc %c CT=%x ",ccc,CT);
}
}
- 15. 15
ここまで
● 関係ないけど…
● Lispプログラマ、Prologプログラマ募集中
● ルールベースの人工知能 開発中
● 機械学習も取り込んだ、ハイブリッドAI
● 普通の32bit or 64bitマシンが対象です
- 19. 19
古い素朴なインタープリタ実現
● 関数実行の本体(中心部)は 「eval」と いう関数
● evalが、eval自身を再帰的に呼び出す実現が素朴に行われている
● 新しい関数を実行するたびに、
evalが呼び出される。
● そして、前のevalに戻 るための情報を、常に記憶
● 実行対象のソースコード が末尾再帰になっていても…
前のevalのための情報が必ず記憶され、まったく最適化(節約)され
ない
● 模式evalで、eval中からevalを再帰的に呼び出す
● このeval呼び出しによっ て、
「残りを実行」のための情報を記憶する
● 呼び出しの度に、記憶している情報はどんどん増える。
- 20. 20
テイル・リカーシブなeval
eval(関数)
{
eval_loop:
:
関数をどんどん実行する
:
if(関数呼び出しに出会った){
if(新しい関数呼び出しの後に、仕事はある?){
今evalしている情報を、スタックへ退避
}
プログラムカウンタ=新しい関数;
goto eval_loop;
}
※1
残りを実行
:
※2
if(スタック!=空){
スタックから、情報を戻す
goto eval_loop;
}
}
- 22. 22
テイル・リカーシブなeval
● evalそのものが大きなループになっている
● 新しい関数の実行をしても、evalの呼び出しは深くならない。
● 関数の末尾からの関数呼び出しは、何も記憶する必要がない
● テイル・リカーシブ・インタープリタは、何も記憶しない。
● 関数が自分自身を呼び出していない時も、最適化される
● 実行途中の関数を継続(再開)するために必要な情報は、
ソフトウェアで作った スタックに格納する。
● 当然に、テイル・リカーシブでない呼び出しは、
普通に記憶を消費する。
- 23. 23
テイル・リカーシブなeval
● 関数の末尾からの関数呼び出しは、何も記憶する必要がな
い。
● テイル・リカーシブ・インタープリタは、何も記憶しない。
↓
● テイル・リカーシブ・インタープリタは、
局所しか見ない、単純な構成のインタープリタでも、
末尾再帰ループの場合に、無駄な 記憶を消費することがない
● Prologインタープリタや、コンパイルされたコードを実行する仮
想マシンのインタープリタ(実行系)は、
テイル・リカーシブ・インタープリタとして実現されているのが、
普通である。
- 25. 25
Robot言語とは
● 再帰的な曲線を描くための言語
● タートル・グラフィックスで画を描く
● 非常に単純なプログラミング言語
● 繰り返し回数を記憶するために、Accが一つだけある
● オリジナルのRobot仕様書 & 実装
Litchen Wang:
An Interactive programming Language for
control of robots, DDJ, Vol.2, Issue 10,
pp.60-63 (1977).
● 日本での紹介文書
石田晴久: ロボット言語, bit,Vol10, No.7, pp.35-
50(1978))
● たけおかのページ
http://www.takeoka.org/~take/kvm/robj.html
- 26. 26
文法
<文> ::= <項><関数> | <項>(<文>) | <文><文>
● Robotは<文>を実行します。
● <項>はすぐ後のものの繰り返し回数を表わします。
<項> ::= a | <数> | 「何もなし」
● 「何もなし」は1を意味します。
● aはAccの内容を意味します。
<数> ::= 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | <数><数>
● 0は2^31を意味します。
<関数> ::= 「組み込み関数」 | 「ユーザ関数」
● 「組み込み関数」、「ユーザ関数」ともに以下。
- 27. 27
組み込み関数
● +
● 1+ Accをインクリメント
● -
● 1- Accをデクリメント
● h
● Home 画面中央部に移動
● n
● North 画面上方を向く
● c
● Clear 画面を消去
● r
● Rotate 45度右へ回る
● f
● Forward 線を引きながら1step進む
● j
● Jump 線を引かずに1step進む
● t(<非ゼロ文>)(<ゼロ文>)
● Test Accが0でないなら<非ゼロ文>のみを
● Accが0なら<ゼロ文>のみを実行する
● dF(<定義文>)
● defun ユーザ関数Fを<定義文>として定義する
- 28. 28
予約語
● a
● Acc 項になってAccの値を示す
● このRobotにはAccが一つだけある
● (0-2^31の値を取る)
● :
● コマンドであることをしめす。
● コマンドは本Robot独自の機能である。
● Robotの言語仕様にはない。
- 29. 29
ユーザ関数
● 英小文字かつ予約されていない一文字がユーザ関数名として使
えます。
● dでdefineする
- 30. 30
コマンド(独自拡張)
● コマンドはKRobot独自の機能である。
● コマンドは実行管理環境(トップレベル)に対する指令である。
● :d
● ユーザ関数の全ての定義を表示する
● :n
● ユーザ関数をすべて消去する
● :<項>s
● f関数で進む距離をドット数で指定する
● コマンドを実行する場合も文を入力した後、 DoItでトップレベルに評価さ
せる。
● 一部のコマンドは、それを評価することによって、PC,スタックなどに影響を
与えてしまう。
● よって、一部のコマンド評価後はContはできなくなる。