Diff
Not logged in

Differences From Artifact [720b71facce28489]:

To Artifact [56b12828066b590e]:


566 566 </p> 567 567 568 568 569 569 <script>explorer.outline.incSymbolLevel();</script> 570 570 <dl> 571 571 <script>explorer.outline.writeEnabled = true;</script> 572 572 <dt><span class="decl"> 573 -<span class="currsymbol">使い方</span> 574 -<script>explorer.outline.addDecl('使い方');</script> 573 +<span class="currsymbol">概要</span> 574 +<script>explorer.outline.addDecl('概要');</script> 575 + 576 +</span></dt> 577 +<script>explorer.outline.writeEnabled = false;</script> 578 + 579 + <dd><p> 580 +samples/macro.pmy にいくつか使い方サンプルが置いてありますので、詳しくはそちらをどうぞ。 581 +</p> 582 +<pre> 583 + &gt;&gt; @macro( twice(print("Hello")) ) 584 + { 585 + pos: {lineno:1, column:9, filename:<REPL>}, 586 + args: [ { pos: {lineno:1, column:15, filename:<REPL>}, 587 + args: [{pos:{lineno:1, column:21, filename:<REPL>}, 588 + is:Str, 589 + data:Hello}], 590 + is: App, 591 + fun: {pos:{lineno:1, column:15, filename:<REPL>}, is:Var, name:print}} 592 + ], 593 + is: App, 594 + fun: {pos:{lineno:1, column:9, filename:<REPL>}, is:Var, name:twice} 595 + } 596 +</pre> 597 +<p> 598 +詳細は気にしなくて構いませんが、とにかく、<tt>@macro</tt> レイヤでは、 599 +基本的には、コードを実行するとそのコードの構文木がでてきます。 600 +この挙動は <tt>@macro</tt> レイヤの変数をセットすることで、カスタマイズできます。 601 +</p> 602 +<pre> 603 + &gt;&gt; @macro twice(x) { x; x } in twice(print("Hello")) 604 + Hello 605 + Hello 606 + Hello 607 +</pre> 608 +<p> 609 +(3回出力されてますが、3個目は <tt>print(x)</tt> の返値は <tt>x</tt> なので、 610 +それがREPLによって印字されているだけです。) 611 +<tt>@macro</tt> レイヤで <tt>in</tt> 以降を実行すると、<tt>print("Hello")</tt> という式を表す構文木が作られ、 612 +それが <tt>twice</tt> 関数に渡されます。<tt>twice</tt> の中身も <tt>@macro</tt> レイヤで実行されるので、 613 +構文木を作ろうとしますが、変数 <tt>x</tt> には <tt>@macro</tt> レイヤで値が入っているので、 614 +その値を読み取って構文木を作成します。 615 +結果として、2回 <tt>print("Hello")</tt> する構文木が作られて、 616 +その後で、それが <tt>@value</tt> レイヤで実行されています。 617 +</p> 618 +<p> 619 +本当にベタに構文木を作るだけなので、変数名の衝突などなどは気にしません。「衛生的でない」マクロです。 620 +</p> 621 +<pre> 622 + @macro LetItBe(x, y) { var <b>it</b> = x; y }; <font color=green># y の中で変数 it が使える</font> 623 + print( LetItBe("myself", "when I find " ~ <b>it</b> ~ " in times of trouble") ); 624 +</pre> 625 +<p> 626 +変数名に気をつけるには、組み込み関数 <tt>gensym()</tt> を使って頑張って下さい。 627 +</p> 628 +</dd> 629 + 630 +<script>explorer.outline.writeEnabled = true;</script> 631 +<dt><span class="decl"> 632 +<span class="currsymbol">レイヤ切り替え</span> 633 +<script>explorer.outline.addDecl('レイヤ切り替え');</script> 575 634 576 635 </span></dt> 577 636 <script>explorer.outline.writeEnabled = false;</script> 578 637 579 - <dd><pre> 580 - When function is invoked, it first run in the @macro layer, and after that, 581 - it run in the neutral layer. Here is an example. 582 - 583 - &gt;&gt; @macro twice(x) { x; x } 584 - &gt;&gt; def f() { twice(print("Hello")); 999 } 585 - (function:173b6a0:1789720) 586 - &gt;&gt; f() 587 - Hello 588 - Hello 589 - 999 590 - 591 - When the interpreter evaluates f(), it first executes 592 - "twice(print("Hello")); 999" 593 - in the @macro layer. Basically what it does is to just construct its syntax tree. 594 - But, since we have defined the "twice" function in the @macro layer, it is 595 - execute as a function. Resulting syntax tree is 596 - "print("Hello"); print("Hello"); 999" 597 - and this is executed on the neutral (in this example, @value) layer. 598 - This is the reason why you see two "Hello"s. 599 - 600 - [[quote and unquote]] 601 - 602 - Here is more involved example of code genration. 603 - From "x", it generates "x*x*x*x*x*x*x*x*x*x". 604 - 605 - @macro pow10(x) { 606 - @value( 607 - def pow(x, n) { 608 - if( n == 1 ) { x } 609 - else { 610 - @macro( @value(x) * @value(pow(x,n-1)) ) 611 - } 612 - } 613 - in 614 - pow(@macro(x),10) 615 - ) 616 - }; 617 - 618 - Here, x is a syntax tree but n is an actual integer. If you read carefully, 619 - you should get what is going on. Basically, @macro can be considered like 620 - quasiquoting and @value to be an escape from it. 638 + <dd><p> 639 +他のレイヤ同様、<tt>@macro</tt> レイヤを実行中に <tt>@layer( ... )</tt> 構文を使うことで、 640 +別のレイヤでコードを動かすこともできます。よく使う例は、<tt>@value</tt> 641 +レイヤに移ることで構文木を普通に計算して色々プログラム的にいじる用途です。 642 +</p> 643 +<pre> 644 + @macro reverseArgs(e) {<b>@value</b>( 645 + def rev(xs, acc) { 646 + case xs when {car:x, cdr:xs}: rev(xs, {car:x, cdr:acc}) when {}: acc 647 + }; 648 + case @macro(e) 649 + when {is:"App", fun:f, args:as}: {is:"App", fun:f, args:rev(as,{})} 650 + when e: e 651 + )}; 652 + print( reverseArgs(1-2) ); <font color=green># 2-1 == 1</font> 621 653 </pre> 622 654 <p> 655 +<tt>reverseArgs</tt> は、関数呼び出しの構文木の、引数の順番を逆転する関数です。 656 +<tt>@macro(e)</tt> によってマクロレイヤにセットされている構文木引数を取り出し、 657 +それを <tt>@value</tt> レイヤによる普通の計算プログラムで操作しています。 658 +要は、<tt>@macro(...)</tt> はいわゆる「準クオート (quasiquote)」、 659 +<tt>@value(...)</tt> は「逆クオート (unquote)」に近い働きをします。 660 +</p> 661 +<p> 662 +<tt>@layer(...)</tt> だけでなく、関数のレイヤ指定引数なども同様に使うことができるので、 663 +一部の引数は <tt>@macro</tt>、一部の引数は <tt>@value</tt> レイヤで受け取る関数を書くなど、 664 +さらに色々面白いことが可能です。 665 +</p> 666 +</dd> 667 + 668 +<script>explorer.outline.writeEnabled = true;</script> 669 +<dt><span class="decl"> 670 +<span class="currsymbol">構文木の構造</span> 671 +<script>explorer.outline.addDecl('構文木の構造');</script> 672 + 673 +</span></dt> 674 +<script>explorer.outline.writeEnabled = false;</script> 675 + 676 + <dd><p> 623 677 構文木がどのようなテーブルで渡されてくるかについては、ソースドキュメントの 624 678 <a href="http://www.kmonos.net/repos/polemy/doc/tip/doc/ast.html">polemy.ast</a> 625 679 のページをご覧下さい。例えば変数名を表す <code>Var</code> クラスには、 626 680 継承の分も合わせて 627 681 <tt><a href="http://www.kmonos.net/repos/polemy/doc/tip/doc/failure.html">LexPosition</a> pos;</tt> 628 682 と <tt>string name;</tt> の2つのメンバがあるので 629 683 </p> ................................................................................ 632 686 pos: {filename:"foo.pmy", lineno:123, column:45}, 633 687 name: "x" } 634 688 </pre> 635 689 <p> 636 690 こんな感じのテーブルになります。 637 691 クラス名が <tt>is</tt> フィールドに、メンバ変数はそのままの名前で入ります。 638 692 配列メンバは cons リストになって入ってきます。 693 +自分で構文木を作る時は、<tt>pos</tt> フィールドだけは省略しても構いません。 639 694 </p> 640 695 </dd> 641 696 642 697 <script>explorer.outline.writeEnabled = true;</script> 643 698 <dt><span class="decl"> 644 -<span class="currsymbol">微妙な挙動</span> 645 -<script>explorer.outline.addDecl('微妙な挙動');</script> 699 +<span class="currsymbol">微妙なところ</span> 700 +<script>explorer.outline.addDecl('微妙なところ');</script> 646 701 647 702 </span></dt> 648 703 <script>explorer.outline.writeEnabled = false;</script> 649 704 650 - <dd><pre> 705 + <dd><p> 706 +ここまで、<tt>@macro</tt> が本当にただの1レイヤであるかのように説明してきましたが、 707 +実はちょっと幾つかのトリックが潜んでいます。 708 +</p> 709 +<pre> 710 + &gt;&gt; @macro twice(x) {x; x} in twice(<b>@value</b>(print("Hello"))) 711 + Hello 712 + Hello 713 + Hello 714 +</pre> 715 +<p> 716 +先ほどの例に <tt>@value</tt> を増やしたものですが、これでもやはり、Hello 717 +が2回 print されるようになります。 718 +</p> 719 +<pre> 720 +<tt>@macro</tt> レイヤと <tt>(rawmacro)</tt> レイヤという二つが協調して動作しています。 651 721 (rawmacro) レイヤの話 652 722 653 723 [[limitations]] 654 724 655 725 This @macro layer is a very primitive one, and not a perfect macro language. 656 726 Two major limitations are seen in the following "it" example. 657 727 ................................................................................ 803 873 <script>explorer.outline.decSymbolLevel();</script> 804 874 805 875 806 876 </td></tr> 807 877 <tr><td id="docfooter"> 808 878 Page was generated with 809 879 <img src="candydoc/img/candydoc.gif" style="vertical-align:middle; position:relative; top:-1px"> 810 - on Thu Nov 25 12:30:12 2010 880 + on Fri Nov 26 10:02:52 2010 811 881 812 882 </td></tr> 813 883 </table> 814 884 </div> 815 885 <script> 816 886 explorer.packageExplorer.addModule("index"); 817 887 explorer.packageExplorer.addModule("main");