Diff
Not logged in

Differences From Artifact [dc242393e80db0b7]:

To Artifact [a076bfb1003e4c62]:


16 16 17 17 <b>Authors:</b><br> 18 18 k.inaba<br><br> 19 19 <b>License:</b><br> 20 20 NYSL 0.9982 (http://www.kmonos.net/nysl/)<br><br> 21 21 22 22 <p> 23 -このファイルは、言語仕様などの簡単な説明です。 23 +左のサイドバーの "Package" タブをクリックすると実装のソースのドキュメントが読めます。 24 24 </p> 25 25 <p> 26 -あとついでに、左のサイドバーの "Package" タブをクリックすると実装のソースのドキュメントが読めます。 26 +このファイルは、言語仕様などの、やや辞書的な説明です。<br /> 27 +もっとざっくりとした、言語デザインの方向性の魂的なものについては、 28 +「メタプログラミングの会」の発表スライドをご覧下さい。 29 +</p> 30 +<p> 31 +あと、 やたらとマクロの章が長くなっていますが、 この部分は、 32 +レイヤ機能を入れたら自動的にすごく自然にマクロが入るなーと思って、 33 +おまけで実装してみた程度のものです。 34 +あんまり重要ではないので、適当にスルーして下さいませ。 35 +単に、適当に入れたら適当で微妙な部分が多く残ってしまったので注意書きが増えているだけで…。 27 36 </p> 28 37 29 38 30 39 <script>explorer.outline.incSymbolLevel();</script> 31 40 <dl> 32 41 <script>explorer.outline.writeEnabled = true;</script> 33 42 <dt><span class="decl"> ................................................................................ 236 245 </pre> 237 246 <p> 238 247 let-in を縦にチェインしたときだけ、同名変数を破壊的に上書きします 239 248 (再帰関数の定義が"うまく"いっているのはこの上書きのためです)。 240 249 なんでこんなことになっているかというと、 241 250 後で説明する「レイヤ」を使ったときに 242 251 <tt>let foo = ... in @lay foo = ... in ...</tt> 243 -で他レイヤに重ね書きするためであります。 252 +で他レイヤに重ね書きするため、のつもりです。詳しくは後で。 244 253 </p> 245 254 </dd> 246 255 </dl> 247 256 <script>explorer.outline.decSymbolLevel();</script> 248 257 249 258 250 259 </dd> ................................................................................ 288 297 以下のデータ型があります。 289 298 </p> 290 299 <ul> 291 300 <li>整数: <tt>0</tt>, <tt>123</tt>, <tt>456666666666666666666666666666666666666789</tt>, ...</li> 292 301 <li>文字列: <tt>"hello, world!"</tt>, ...</li> 293 302 <li>関数: <tt>fun(x){x+1}</tt></li> 294 303 <li>テーブル: <tt>{car: 1, cdr: {car: 2, cdr: {}}}</tt></li> 295 - <li>未定義値: (特殊なケースで作られます。「レイヤ」の説明参照のこと。)</li> 304 + <li>ボトム: (特殊なケースで作られます。「レイヤ」の説明参照のこと。)</li> 296 305 </ul> 297 306 <p> 298 307 関数はいわゆる「クロージャ」です。静的スコープで外側の環境にアクセスできます。 299 308 テーブルはいわゆるプロトタイプチェーンを持っていて、 300 309 自分にないフィールドの場合は親に問い合わせが行く感じになっていますが、 301 310 フィールドの書き換えがないので、これは特に意味ないかもしれない…。 302 311 </p> ................................................................................ 556 565 </pre> 557 566 <p> 558 567 動きとしてはこうです。 559 568 </p> 560 569 <ol> 561 570 <li>関数呼び出し時(とトップレベル環境の実行開始時)に、 562 571 まず、<code>@macro</code> レイヤでコードを実行。</li> 563 -<li>返ってきた構文木を、<code>@value</code> レイヤ、 564 - またはその関数を呼び出したときのレイヤで実行。</li> 572 +<li>返ってきた構文木を、その関数を呼び出したときのレイヤで実行。</li> 565 573 </ol> 566 574 <p> 567 575 <code>@macro</code> レイヤも所詮ただのレイヤですので、 568 576 上で説明した方法で <code>@macro</code> レイヤに関数などを登録しておくことで、 569 577 構文木の生成をいじることが可能です。まさにマクロ。 570 578 </p> 571 579 ................................................................................ 655 663 )}; 656 664 print( reverseArgs(1-2) ); <font color=green># 2-1 == 1</font> 657 665 </pre> 658 666 <p> 659 667 <tt>reverseArgs</tt> は、関数呼び出しの構文木の、引数の順番を逆転する関数です。 660 668 <tt>@macro(e)</tt> によってマクロレイヤにセットされている構文木引数を取り出し、 661 669 それを <tt>@value</tt> レイヤによる普通の計算プログラムで操作しています。 662 -要は、<tt>@macro(...)</tt> はいわゆる「準クオート (quasiquote)」、 663 -<tt>@value(...)</tt> は「逆クオート (unquote)」に近い働きをします。 670 +<tt>@macro(...)</tt> はいわゆる「準クオート (quasiquote)」、 671 +<tt>@value(...)</tt> は「逆クオート (unquote)」にちょっと近いかもしれません。 664 672 </p> 665 673 <p> 666 674 <tt>@layer(...)</tt> だけでなく、関数のレイヤ指定引数なども同様に使うことができるので、 667 675 一部の引数は <tt>@macro</tt>、一部の引数は <tt>@value</tt> レイヤで受け取る関数を書くなど、 668 676 さらに色々面白いことが可能です。 669 677 </p> 670 678 </dd> ................................................................................ 696 704 配列メンバは cons リストになって入ってきます。 697 705 自分で構文木を作る時は、<tt>pos</tt> フィールドだけは省略しても構いません。 698 706 </p> 699 707 </dd> 700 708 701 709 <script>explorer.outline.writeEnabled = true;</script> 702 710 <dt><span class="decl"> 703 -<span class="currsymbol">微妙なところ</span> 704 -<script>explorer.outline.addDecl('微妙なところ');</script> 711 +<span class="currsymbol">微妙なところ1</span> 712 +<script>explorer.outline.addDecl('微妙なところ1');</script> 705 713 706 714 </span></dt> 707 715 <script>explorer.outline.writeEnabled = false;</script> 708 716 709 717 <dd><p> 710 -ここまで、<tt>@macro</tt> が本当にただの1レイヤであるかのように説明してきましたが、 711 -実はちょっと幾つかのトリックが潜んでいます。 718 +ここまで、<tt>@macro</tt> が本当にただの1レイヤと説明してきましたが、 719 +実はちょっとトリックが潜んでいます。 712 720 </p> 713 721 <pre> 714 722 &gt;&gt; @macro twice(x) {x; x} in twice(<b>@value</b>(print("Hello"))) 715 723 Hello 716 724 Hello 717 725 Hello 718 726 </pre> 719 727 <p> 720 728 先ほどの例に <tt>@value</tt> を増やしたものですが、これでもやはり、Hello 721 -が2回 print されるようになります。 729 +が2回 print されるようになります。これは本来はおかしな話で、<tt>print("Hello")</tt> 730 +は <tt>@value</tt> レイヤで実行されて値に落ちるはずなので、1回しか print されないはず。 731 +</p> 732 +<p> 733 +実は、Polemy の中では、<tt>@macro</tt> レイヤと <tt>(rawmacro)</tt> 734 +レイヤという二つの異なるマクロ用レイヤが動いています。 735 +</p> 736 +<ul> 737 + <li><tt>(rawmacro)</tt> も <tt>@macro</tt> も、コードを動かすとその構文木を返す意味論。</li> 738 + <li>ただし、<tt>(rawmacro)</tt> も <tt>@macro</tt> も、 739 + <tt>@macro</tt> レイヤに値のセットされた変数をみつけたときは、 740 + その変数という構文木を作るのではなく、変数の内容を展開。</li> 741 + <li>また <tt>@macro</tt> は、 742 + レイヤ指定式を見ると実行レイヤを切り替て、構文木生成モードをやめてしまう。</li> 743 + <li><tt>(rawmacro)</tt> は、 744 + レイヤ指定式を見ても実行レイヤを切り替えないで構文木にする。</li> 745 +</ul> 746 +<p> 747 +ユーザーから直接 <tt>(rawmacro)</tt> は呼べませんが、 748 +「関数やトップレベル実行開始前のマクロ処理は <tt>(rawmacro)</tt> で実行開始」 749 +「<tt>@macro</tt> レイヤ以外で呼び出した関数の仮引数に <tt>@macro</tt> がついていたら、 750 +その実引数は <tt>(rawmacro)</tt> で実行」 751 +という2つのタイミングで <tt>(rawmacro)</tt> が動き出します。 752 +<tt>(rawmacro)</tt> が <tt>@macro</tt> レイヤから変数を見つけてマクロし始める時に、 753 +そこで <tt>@macro</tt> に動作が移ります。 754 +</p> 755 +<p> 756 +こうなっているのは、全部がレイヤ指定式に反応する <tt>@macro</tt> の動作だと、 757 +レイヤを使ったプログラムが全て <tt>@value</tt> 実行時ではなく、 758 +マクロ展開の時点で動き始めてしまって、おかしなことになるためです。 759 +色々考えた結果、とりあえずこの中途半端な混合が具合がよいのではないかということになりました。 760 +</p> 761 +</dd> 762 + 763 +<script>explorer.outline.writeEnabled = true;</script> 764 +<dt><span class="decl"> 765 +<span class="currsymbol">微妙なところ2</span> 766 +<script>explorer.outline.addDecl('微妙なところ2');</script> 767 + 768 +</span></dt> 769 +<script>explorer.outline.writeEnabled = false;</script> 770 + 771 + <dd><p> 772 +「関数実行開始時に、まずマクロレイヤを実行」と書きましたが、この時、関数内関数まで辿りにいくので、 773 +何重にもネストした関数を使っていると、内側の関数は、何重にもマクロ展開が走ってしまいます。 774 +これはなにかおかしい気がしますね。Scheme などはどうなっているのか調べないと…。 775 +</p> 776 +</dd> 777 + 778 +<script>explorer.outline.writeEnabled = true;</script> 779 +<dt><span class="decl"> 780 +<span class="currsymbol">微妙なところ3</span> 781 +<script>explorer.outline.addDecl('微妙なところ3');</script> 782 + 783 +</span></dt> 784 +<script>explorer.outline.writeEnabled = false;</script> 785 + 786 + <dd><p> 787 +これはエラーになります。 722 788 </p> 723 789 <pre> 724 -<tt>@macro</tt> レイヤと <tt>(rawmacro)</tt> レイヤという二つが協調して動作しています。 725 - (rawmacro) レイヤの話 726 - 727 - [[limitations]] 728 - 729 - This @macro layer is a very primitive one, and not a perfect macro language. 730 - Two major limitations are seen in the following "it" example. 731 - 732 - &gt;&gt; @macro LetItBe(x, y) { let it = x in y }; 733 - 734 - The variable name is not hygenic, and so without any effort, the syntax tree "y" 735 - can access the outer variable "it". 736 - 737 - &gt;&gt; def foo() { LetItBe( 1+2+3, it*it ) } 738 - &gt;&gt; foo() 739 - 36 740 - 741 - Of course, this is not just a limitation; it can sometimes allow us to write 742 - many interesting macros. 743 - 744 - The other problem is that the macro expansion is only done at function startup. 745 - So 746 - 747 - &gt;&gt; LetItBe( 1+2+3, it*it ) 748 - ...\value.d(173): [<REPL>:24:1] variable LetItBe is not set in layer @value 749 - 750 - you cannot directly use the macro in the same scope as the definition. 751 - You need to wrap it up in a function (like the foo() in the above example). 790 + &gt;&gt; let _ = (@macro twice(x) {x;x} in twice(print("Hello"))) 791 + polemy.failure.RuntimeException@C:\Develop\Projects\Polemy\polemy\value.d(109): 792 + [<REPL>:2:35] 'twice' is not set in @value layer 752 793 </pre> 794 +<p> 795 +どういうことかというと、<tt>@macro</tt> で定義したマクロはいつから使えるようになるかという話で、 796 +この <tt>@macro twice(x) {x;x} in ...</tt> の部分は <tt>@value</tt> レイヤの式なので、 797 +まずこの式全体のマクロ展開が終わったあとにしか実行されないのです。<tt>twice</tt> 798 +がマクロと見なされはじめるのは、<tt>@macro</tt> 実行が終わった後。 799 +なので、 800 +例えば <tt>twice(print("Hello"))</tt> の部分を無名関数にラップしてやれば、 801 +マクロ展開を遅らせられて、 ちゃんと実行ができます。 802 +</p> 803 +<p> 804 +これだと余りにも不便なので、関数のトップレベルの変数宣言式の列についてだけは、 805 +<tt>@macro</tt> と <tt>@value</tt> の評価を交互にインターリーブするようにしました。 806 +「関数やREPLのトップレベルの最初に宣言したマクロだけは、その関数内で即座に使える」わけです。 807 +これも Scheme の let-syntax などなどの動きを調べて勉強しないと…。 808 +</p> 753 809 </dd> 754 810 </dl> 755 811 <script>explorer.outline.decSymbolLevel();</script> 756 812 757 813 758 814 </dd> 759 815 ................................................................................ 877 933 <script>explorer.outline.decSymbolLevel();</script> 878 934 879 935 880 936 </td></tr> 881 937 <tr><td id="docfooter"> 882 938 Page was generated with 883 939 <img src="candydoc/img/candydoc.gif" style="vertical-align:middle; position:relative; top:-1px"> 884 - on Fri Nov 26 16:41:52 2010 940 + on Sat Nov 27 01:54:49 2010 885 941 886 942 </td></tr> 887 943 </table> 888 944 </div> 889 945 <script> 890 946 explorer.packageExplorer.addModule("index"); 891 947 explorer.packageExplorer.addModule("main");