Diff
Not logged in

Differences From Artifact [a7325259b4f09952]:

To Artifact [d2cf6de49dcafd42]:


1 Ddoc 1 Ddoc 2 $(DDOC_AUTHORS k.inaba) 2 $(DDOC_AUTHORS k.inaba) 3 $(DDOC_LICENSE NYSL 0.9982 (http://www.kmonos.net/nysl/)) 3 $(DDOC_LICENSE NYSL 0.9982 (http://www.kmonos.net/nysl/)) 4 4 5 <p> 5 <p> 6 このファイルは、言語仕様などの簡単な説明です。 | 6 左のサイドバーの "Package" タブをクリックすると実装のソースのドキュメントが読めます。 7 </p> 7 </p> 8 <p> 8 <p> 9 とついでに、左イドバーの "Package" タブをクリックすると実装のソースのドキュメントが読めます。 | 9 のファイルは、言語仕様などやや辞書的な説明です。<br /> > 10 もっとざっくりとした、言語デザインの方向性の魂的なもについては、 > 11 「メタプログラミングの会」の発表スライドをご覧下さい > 12 </p> > 13 <p> > 14 あと、 やたらとマクロの章が長くなっていますが、 この部分は、 > 15 レイヤ機能を入れたら自動的にすごく自然にマクロが入るーと思って、 > 16 おまけで実装してみた程度のものです。 > 17 あんまり重要ではないので、適当にスルーして下さいませ > 18 単に、適当に入れたら適当で微妙な部分が多く残ってしまたので注意書きが増えているだけで…。 10 </p> 19 </p> 11 20 12 $(DDOC_MEMBERS 21 $(DDOC_MEMBERS 13 22 14 $(SECTION Syntax, $(SECBODY 23 $(SECTION Syntax, $(SECBODY 15 <p> 24 <p> 16 文法について。 25 文法について。 ................................................................................................................................................................................ 171 </pre> 180 </pre> 172 <p> 181 <p> 173 let-in を縦にチェインしたときだけ、同名変数を破壊的に上書きします 182 let-in を縦にチェインしたときだけ、同名変数を破壊的に上書きします 174 (再帰関数の定義が"うまく"いっているのはこの上書きのためです)。 183 (再帰関数の定義が"うまく"いっているのはこの上書きのためです)。 175 なんでこんなことになっているかというと、 184 なんでこんなことになっているかというと、 176 後で説明する「レイヤ」を使ったときに 185 後で説明する「レイヤ」を使ったときに 177 <tt>let foo = ... in @lay foo = ... in ...</tt> 186 <tt>let foo = ... in @lay foo = ... in ...</tt> 178 で他レイヤに重ね書きするためあります。 | 187 で他レイヤに重ね書きするためのつもりです。詳しくは後で 179 </p> 188 </p> 180 )) 189 )) 181 ) 190 ) 182 )) 191 )) 183 192 184 193 185 194 ................................................................................................................................................................................ 203 以下のデータ型があります。 212 以下のデータ型があります。 204 </p> 213 </p> 205 <ul> 214 <ul> 206 <li>整数: <tt>0</tt>, <tt>123</tt>, <tt>456666666666666666666666666666666666 215 <li>整数: <tt>0</tt>, <tt>123</tt>, <tt>456666666666666666666666666666666666 207 <li>文字列: <tt>"hello, world!"</tt>, ...</li> 216 <li>文字列: <tt>"hello, world!"</tt>, ...</li> 208 <li>関数: <tt>fun(x){x+1}</tt></li> 217 <li>関数: <tt>fun(x){x+1}</tt></li> 209 <li>テーブル: <tt>{car: 1, cdr: {car: 2, cdr: {}}}</tt></li> 218 <li>テーブル: <tt>{car: 1, cdr: {car: 2, cdr: {}}}</tt></li> 210 <li>未定義値: (特殊なケースで作られます。「レイヤ」の説明参照のこと。)</li> | 219 <li>ボトム: (特殊なケースで作られます。「レイヤ」の説明参照のこと。)</li> 211 </ul> 220 </ul> 212 <p> 221 <p> 213 関数はいわゆる「クロージャ」です。静的スコープで外側の環境にアクセスできます。 222 関数はいわゆる「クロージャ」です。静的スコープで外側の環境にアクセスできます。 214 テーブルはいわゆるプロトタイプチェーンを持っていて、 223 テーブルはいわゆるプロトタイプチェーンを持っていて、 215 自分にないフィールドの場合は親に問い合わせが行く感じになっていますが、 224 自分にないフィールドの場合は親に問い合わせが行く感じになっていますが、 216 フィールドの書き換えがないので、これは特に意味ないかもしれない…。 225 フィールドの書き換えがないので、これは特に意味ないかもしれない…。 217 </p> 226 </p> ................................................................................................................................................................................ 444 </pre> 453 </pre> 445 <p> 454 <p> 446 動きとしてはこうです。 455 動きとしてはこうです。 447 </p> 456 </p> 448 <ol> 457 <ol> 449 <li>関数呼び出し時(とトップレベル環境の実行開始時)に、 458 <li>関数呼び出し時(とトップレベル環境の実行開始時)に、 450 まず、<code>@macro</code> レイヤでコードを実行。</li> 459 まず、<code>@macro</code> レイヤでコードを実行。</li> 451 <li>返ってきた構文木を、<code>@value</code> レイヤ、 < 452 またはその関数を呼び出したときのレイヤで実行。</li> | 460 <li>返ってきた構文木を、その関数を呼び出したときのレイヤで実行。</li> 453 </ol> 461 </ol> 454 <p> 462 <p> 455 <code>@macro</code> レイヤも所詮ただのレイヤですので、 463 <code>@macro</code> レイヤも所詮ただのレイヤですので、 456 上で説明した方法で <code>@macro</code> レイヤに関数などを登録しておくことで、 464 上で説明した方法で <code>@macro</code> レイヤに関数などを登録しておくことで、 457 構文木の生成をいじることが可能です。まさにマクロ。 465 構文木の生成をいじることが可能です。まさにマクロ。 458 </p> 466 </p> 459 467 ................................................................................................................................................................................ 526 )}; 534 )}; 527 print( reverseArgs(1-2) ); $(D_COMMENT # 2-1 == 1) 535 print( reverseArgs(1-2) ); $(D_COMMENT # 2-1 == 1) 528 </pre> 536 </pre> 529 <p> 537 <p> 530 <tt>reverseArgs</tt> は、関数呼び出しの構文木の、引数の順番を逆転する関数です。 538 <tt>reverseArgs</tt> は、関数呼び出しの構文木の、引数の順番を逆転する関数です。 531 <tt>@macro(e)</tt> によってマクロレイヤにセットされている構文木引数を取り出し、 539 <tt>@macro(e)</tt> によってマクロレイヤにセットされている構文木引数を取り出し、 532 それを <tt>@value</tt> レイヤによる普通の計算プログラムで操作しています。 540 それを <tt>@value</tt> レイヤによる普通の計算プログラムで操作しています。 533 要は、<tt>@macro(...)</tt> はいわゆる「準クオート (quasiquote)」、 | 541 <tt>@macro(...)</tt> はいわゆる「準クオート (quasiquote)」、 534 <tt>@value(...)</tt> は「逆クオート (unquote)」に近い働きをします。 | 542 <tt>@value(...)</tt> は「逆クオート (unquote)」にちょっと近いかもしれません 535 </p> 543 </p> 536 <p> 544 <p> 537 <tt>@layer(...)</tt> だけでなく、関数のレイヤ指定引数なども同様に使うことができるので、 545 <tt>@layer(...)</tt> だけでなく、関数のレイヤ指定引数なども同様に使うことができるので、 538 一部の引数は <tt>@macro</tt>、一部の引数は <tt>@value</tt> レイヤで受け取る関数を書くなど、 546 一部の引数は <tt>@macro</tt>、一部の引数は <tt>@value</tt> レイヤで受け取る関数を書くなど、 539 さらに色々面白いことが可能です。 547 さらに色々面白いことが可能です。 540 </p> 548 </p> 541 )) 549 )) ................................................................................................................................................................................ 556 <p> 564 <p> 557 こんな感じのテーブルになります。 565 こんな感じのテーブルになります。 558 クラス名が <tt>is</tt> フィールドに、メンバ変数はそのままの名前で入ります。 566 クラス名が <tt>is</tt> フィールドに、メンバ変数はそのままの名前で入ります。 559 配列メンバは cons リストになって入ってきます。 567 配列メンバは cons リストになって入ってきます。 560 自分で構文木を作る時は、<tt>pos</tt> フィールドだけは省略しても構いません。 568 自分で構文木を作る時は、<tt>pos</tt> フィールドだけは省略しても構いません。 561 </p> 569 </p> 562 )) 570 )) 563 $(SECTION 微妙なところ, $(SECBODY | 571 $(SECTION 微妙なところ, $(SECBODY 564 <p> 572 <p> 565 ここまで、<tt>@macro</tt> が本当にただの1レイヤあるかのように説明してきましたが、 | 573 ここまで、<tt>@macro</tt> が本当にただの1レイヤ説明してきましたが、 566 実はちょっと幾つかのトリックが潜んでいます。 | 574 実はちょっとトリックが潜んでいます。 567 </p> 575 </p> 568 <pre> 576 <pre> 569 &gt;&gt; @macro twice(x) {x; x} in twice($(B @value)(print("Hello"))) 577 &gt;&gt; @macro twice(x) {x; x} in twice($(B @value)(print("Hello"))) 570 Hello 578 Hello 571 Hello 579 Hello 572 Hello 580 Hello 573 </pre> 581 </pre> 574 <p> 582 <p> 575 先ほどの例に <tt>@value</tt> を増やしたものですが、これでもやはり、Hello 583 先ほどの例に <tt>@value</tt> を増やしたものですが、これでもやはり、Hello 576 が2回 print されるようになります。 | 584 が2回 print されるようになります。これは本来はおかしな話で、<tt>print("Hello")</tt> > 585 は <tt>@value</tt> レイヤで実行されて値に落ちるはずなので、1回しか print されないはず。 > 586 </p> > 587 <p> > 588 実は、Polemy の中では、<tt>@macro</tt> レイヤと <tt>(rawmacro)</tt> > 589 レイヤという二つの異なるマクロ用レイヤが動いています > 590 </p> > 591 <ul> > 592 <li><tt>(rawmacro)</tt> も <tt>@macro</tt> も、コードを動かすとそ構文木を返す意味論。</li> > 593 <li>ただし、<tt>(rawmacro)</tt> も <tt>@macro</tt> も、 > 594 <tt>@macro</tt> レイヤに値のセットされた変数をみつけたとは、 > 595 その変数という構文木を作るのではなく、変数の内容を展開。</li> > 596 <li>また <tt>@macro</tt> は、 > 597 レイヤ指定式を見ると実行レイヤを切り替て、構文木生成モードをやめてしまう。</li> > 598 <li><tt>(rawmacro)</tt> は、 > 599 レイヤ指定式を見ても実行レイヤを切り替えないで構文木にする。</li> > 600 </ul> > 601 <p> > 602 ユーザーから直接 <tt>(rawmacro)</tt> は呼べませんが、 > 603 「関数やトップレベル実行開始前のマクロ処理は <tt>(rawmacro)</tt> で実行開始」 > 604 「<tt>@macro</tt> レイヤ以外で呼び出した関数の仮引数に <tt>@macro</tt> がついていたら、 > 605 その実引数は <tt>(rawmacro)</tt> で実行」 > 606 という2つのタイミングで <tt>(rawmacro)</tt> が動き出します > 607 <tt>(rawmacro)</tt> が <tt>@macro</tt> レイヤから変数を見つけてマロし始める時に、 > 608 そこで <tt>@macro</tt> に動作が移ります。 > 609 </p> > 610 <p> > 611 こうなっているのは、全部がレイヤ指定式に反応する <tt>@macro</tt> の動作だと、 > 612 レイヤを使ったプログラムが全て <tt>@value</tt> 実行時ではなく、 > 613 マクロ展開の時点で動き始めてしまって、おかしなことにるためです。 > 614 色々考えた結果、とりあえずこの中途半端な混合が具合がいのではないかということになりました。 > 615 </p> > 616 )) > 617 $(SECTION 微妙なところ2, $(SECBODY > 618 <p> > 619 「関数実行開始時に、まずマクロレイヤを実行」と書きまたが、この時、関数内関数まで辿りにいくので、 > 620 何重にもネストした関数を使っていると、内側の関数は、重にもマクロ展開が走ってしまいます。 > 621 これはなにかおかしい気がしますね。Scheme などはどうなっいるのか調べないと…。 > 622 </p> > 623 )) > 624 $(SECTION 微妙なところ3, $(SECBODY > 625 <p> > 626 これはエラーになります。 577 </p> 627 </p> 578 <pre> 628 <pre> 579 <tt>@macro</tt> レイヤと <tt>(rawmacro)</tt> レイヤという二つが協調して動作しています。 | 629 &gt;&gt; let _ = (@macro twice(x) {x;x} in twice(print("Hello"))) 580 (rawmacro) レイヤの話 | 630 polemy.failure.RuntimeException@C:\Develop\Projects\Polemy\polemy\value.d(10 581 < 582 [[limitations]] < 583 < 584 This @macro layer is a very primitive one, and not a perfect macro language. < 585 Two major limitations are seen in the following "it" example. < 586 < 587 >> @macro LetItBe(x, y) { let it = x in y }; < 588 < 589 The variable name is not hygenic, and so without any effort, the syntax tree < 590 can access the outer variable "it". < 591 < 592 >> def foo() { LetItBe( 1+2+3, it*it ) } < 593 >> foo() < 594 36 < 595 < 596 Of course, this is not just a limitation; it can sometimes allow us to write < 597 many interesting macros. < 598 < 599 The other problem is that the macro expansion is only done at function startu < 600 So < 601 < 602 >> LetItBe( 1+2+3, it*it ) < 603 ...\value.d(173): [<REPL>:24:1] variable LetItBe is not set in layer @value < 604 < 605 you cannot directly use the macro in the same scope as the definition. < 606 You need to wrap it up in a function (like the foo() in the above example). < > 631 [<REPL>:2:35] 'twice' is not set in @value layer 607 </pre> 632 </pre> > 633 <p> > 634 どういうことかというと、<tt>@macro</tt> で定義したマクロはつから使えるようになるかという話で、 > 635 この <tt>@macro twice(x) {x;x} in ...</tt> の部分は <tt>@value</tt> レイヤの式なので、 > 636 まずこの式全体のマクロ展開が終わったあとにしか実行さないのです。<tt>twice</tt> > 637 がマクロと見なされはじめるのは、<tt>@macro</tt> 実行が終わた後。 > 638 なので、 > 639 例えば <tt>twice(print("Hello"))</tt> の部分を無名関数にラップしてやれば、 > 640 マクロ展開を遅らせられて、 ちゃんと実行ができます。 > 641 </p> > 642 <p> > 643 これだと余りにも不便なので、関数のトップレベルの変数言式の列についてだけは、 > 644 <tt>@macro</tt> と <tt>@value</tt> の評価を交互にインターリーブるようにしました。 > 645 「関数やREPLのトップレベルの最初に宣言したマクロだけはその関数内で即座に使える」わけです。 > 646 これも Scheme の let-syntax などなどの動きを調べて勉強しないと…。 > 647 </p> 608 )) 648 )) 609 ) 649 ) 610 )) 650 )) 611 651 612 652 613 $(SECTION Built-in Primitives, $(SECBODY 653 $(SECTION Built-in Primitives, $(SECBODY 614 <p> 654 <p>