Artifact Content
Not logged in

Artifact b0a85a436fa9ea4b9085dc2dbc94f959e805f772


     1  Ddoc
     2  $(DDOC_AUTHORS k.inaba)
     3  $(DDOC_LICENSE NYSL 0.9982 (http://www.kmonos.net/nysl/))
     4  
     5  <p>
     6  左のサイドバーの "Package" タブをクリックすると実装のソースのドキュメントが読めます。
     7  </p>
     8  <p>
     9  このファイルは、言語仕様などの、やや辞書的な説明です。<br />
    10  もっとざっくりとした、言語デザインの方向性の魂的なものについては、
    11  「メタプログラミングの会」の発表スライドをご覧下さい。
    12  </p>
    13  <p>
    14  あと、 やたらとマクロの章が長くなっていますが、 この部分は、
    15  レイヤ機能を入れたら自動的にすごく自然にマクロが入るなーと思って、
    16  おまけで実装してみた程度のものです。
    17  あんまり重要ではないので、適当にスルーして下さいませ。
    18  単に、適当に入れたら適当で微妙な部分が多く残ってしまったので注意書きが増えているだけで…。
    19  </p>
    20  <p>
    21  言い訳ついでにもう一つ言い訳ですが、この言語は、少なくとも今のところ、
    22  実用に使うことを考えた設計にはなっていません。どちらかというと、
    23  Brainfuck や Unlambda や Whitespace の仲間と思ってお使い下さい。
    24  </p>
    25  
    26  $(DDOC_MEMBERS
    27  
    28  $(SECTION Syntax, $(SECBODY
    29  <p>
    30  文法について。
    31  字句解析がわりと適当なので、
    32  変数宣言の変数名のところに、数字を変数名として使えて参照できない変数が作れたり、
    33  予約語は予約語として解釈され得ないところでは普通に変数名として使えちゃったりして、
    34  偶にとんでもない見かけのソースが構文解析通りますが、気にしないで適当に使って下さい。
    35  </p>
    36  
    37  $(DDOC_MEMBERS
    38  
    39  $(SECTION 文字コード, $(SECBODY
    40  <p>
    41  UTF-8 のみ対応です。
    42  </p>
    43  ))
    44  
    45  $(SECTION コメント, $(SECBODY
    46  <p>
    47  行コメントは <tt>#</tt> から改行までです。
    48  </p>
    49  <p>
    50  ブロックコメントはありません。
    51  </p>
    52  ))
    53  
    54  $(SECTION BNF, $(SECBODY
    55  <pre>
    56   ID    ::= 適当に識別子っぽい文字列
    57   LAYER ::= "@" ID
    58  
    59   E ::=
    60     $(D_COMMENT # 変数宣言)
    61       | DECL "=" E (";"|"in") E
    62       | DECL "(" PARAMS ")" "{" E "}" (";"|"in") E
    63       | DECL "=" E
    64       | DECL "(" PARAMS ")" "{" E "}"
    65  
    66           where DECL ::= ("var"|"let"|"def"|LAYER) ID | "@" LAYER
    67  
    68     $(D_COMMENT # リテラル)
    69       | INTEGER                        $(D_COMMENT # 非負整数)
    70       | STRING                         $(D_COMMENT # "" でくくった文字列。\" と \\ は使える)
    71       | "{" ENTRYS "}"                 $(D_COMMENT # テーブル)
    72       | "fun" "(" PARAMS ")" "{" E "}" $(D_COMMENT # 無名関数)
    73       |  "λ" "(" PARAMS ")" "{" E "}" $(D_COMMENT # 無名関数)
    74  
    75     $(D_COMMENT # 関数呼び出し)
    76       | E "(" ARGS")"
    77  
    78           where    ARGS ::= E "," ... "," E
    79                  PARAMS ::= (ID|LAYER)+ "," ... "," (ID|LAYER)+
    80                  ENTRYS ::= ID ":" E    "," ... "," ID ":" E
    81  
    82     $(D_COMMENT # 演算子など)
    83       | "(" E ")"                 $(D_COMMENT # ただの括弧)
    84       | "..."                     $(D_COMMENT # これを実行するとdie)
    85       | E BINOP E                 $(D_COMMENT # 二項演算子いろいろ)
    86       | E "."  ID                 $(D_COMMENT # テーブルのフィールドアクセス)
    87       | E ".?" ID                 $(D_COMMENT # テーブルにフィールドがあるか否か)
    88       | E "{" ENTRYS "}"          $(D_COMMENT # テーブル拡張)
    89       | "if" E ("then"|":"|"then" ":") E
    90       | "if" E ("then"|":"|"then" ":") E "else" ":"? E
    91  
    92     $(D_COMMENT # パターンマッチ)
    93       | "case" E ("when" PATTERN ":" E )* 
    94  
    95           where PATTERN ::= 式がだいたいなんでも書ける気がする
    96  
    97     $(D_COMMENT # レイヤ指定実行)
    98       | LAYER "(" E ")"
    99  </pre>
   100  ))
   101  
   102  $(SECTION 糖衣構文, $(SECBODY
   103  <p>
   104  演算子というものはありません。内部的には全て関数呼び出し構文に書き換えられています。<tt>if</tt> もです。
   105  <br/>
   106  パターンマッチも全部 <tt>if</tt> と <tt>==</tt> と <tt>&amp;&amp;</tt> と
   107  <tt>.</tt> と <tt>.?</tt> を使った関数呼び出し式に書き換えられていますが、
   108  規則の詳細を説明するのが面倒なので適当に想像して下さい。
   109  他の書き換えはこんな感じです。
   110  </p>
   111  <pre>
   112      if E then E         ⇒ if( E, fun(){E}, fun(){} )
   113      if E then E else E  ⇒ if( E, fun(){E}, fun(){E} )
   114      E BINOP E           ⇒ BINOP(E, E)
   115      { ENTRIES }         ⇒ {}{ ENTRIES }
   116      {}                  ⇒ {}()
   117      E {ID:E, ...}       ⇒ .=(E, ID, E) { ... }
   118  </pre>
   119  <p>
   120  変数宣言に色々ありますが、<tt>let</tt> と <tt>var</tt> と <tt>def</tt> は同じ扱いで、
   121  <tt>in</tt> と <tt>;</tt> は同じ扱いです。つまり
   122  </p>
   123  <pre>
   124     let x = E in E
   125     var x = E in E
   126     def x = E in E
   127     let x = E ; E
   128     var x = E ; E
   129     def x = E ; E
   130  </pre>
   131  <p>
   132  以上のどれも同じ意味なので、なんとなく関数型っぽく書きたい気分の日は <tt>let in</tt> を、
   133  手続き型っぽく書きたい気分の日は <tt>var ;</tt> を使うとよいと思います。
   134  <tt>if then else</tt> も微妙にコロンがあったりなかったりバリエーションがありますが好みで使います。
   135  </p>
   136  <p>
   137  関数を宣言するときは、<tt>fun</tt> や <tt>λ</tt> を省略できます。
   138  以下の書き換えが行われます。
   139  </p>
   140  <pre>
   141     def f( ARGS ) { E }; E   ⇒   def f = fun(ARGS){E}; E
   142  </pre>
   143  <p>
   144  他に、もっと手続き型っぽくための書き換え色々
   145  </p>
   146  <pre>
   147     fun () { E; E; E      }   ⇒   fun () { let _ = E in let _ = E in E }
   148     fun () { var x = 100  }   ⇒   fun () { var x = 100; x }
   149     fun () { var x = 100; }   ⇒   fun () { var x = 100; x }
   150     fun () { }                ⇒   fun () { "(empty function body)" }
   151  </pre>
   152  <p>
   153  中身が空の関数に何を返させるかは適当です。今はとりあえず適当に文字列返してます。
   154  </p>
   155  ))
   156  
   157  $(SECTION 変数のスコープ規則, $(SECBODY
   158  <p>
   159  基本的には、let によって常識的な感じに変数のスコープがネストします。
   160  </p>
   161  <pre>
   162     let x=21 in let x=x+x in x    $(D_COMMENT # 42)
   163  </pre>
   164  <p>
   165  一方で、"let rec" のような特別な構文はありませんが、
   166  </p>
   167  <pre>
   168     let f = fun(x) { if x==0 then 1 else x*f(x-1) } in f(10)  $(D_COMMENT # 3628800)
   169  </pre>
   170  <p>
   171  再帰的な関数定義なども、おそらく意図されたとおりに動きます。
   172  内部の詳細は、諸般の事情により、
   173  マジカルで破壊的なスコープ規則になっているのですが、
   174  同名の変数を激しく重ねて使ったりしなければ、
   175  だいたい自然な動きをすると思います、たぶん、はい。
   176  </p>
   177  <p>
   178  ひとつだけ不可思議な動きをするのは、以下のケースです。
   179  </p>
   180  <pre>
   181     let x = 1 in
   182     let f = fun() {x} in
   183     let x = 2 in
   184        f()    $(D_COMMENT # 2!!)
   185  </pre>
   186  <p>
   187  let-in を縦にチェインしたときだけ、同名変数を破壊的に上書きします
   188  (再帰関数の定義が"うまく"いっているのはこの上書きのためです)。
   189  なんでこんなことになっているかというと、
   190  後で説明する「レイヤ」を使ったときに
   191  <tt>let foo = ... in @lay foo = ... in ...</tt>
   192  で他レイヤに重ね書きするため、のつもりです。詳しくは後で。
   193  </p>
   194  ))
   195  )
   196  ))
   197  
   198  
   199  
   200  
   201  $(SECTION Basic Features, $(SECBODY
   202  <p>
   203  特に特徴的でもない部分を簡単にまとめ。
   204  </p>
   205  <ul>
   206    <li>静的型システムはありません。</li>
   207    <li>"ほぼ" 純粋関数型言語です。変数やテーブルのフィールドの破壊的な書き換えはできません。<br/>
   208        ただし、組み込み関数(<tt>print</tt>)と、変数のスコープ規則のマジカルな片隅に副作用があります。</li>
   209  </ul>
   210  <p>
   211  静的型システムがないのは意図的ですが、破壊的代入がないのは、単に実装がめんどかっただけなので、
   212  今後何か増えるかもしれません。増えないかもしれません。
   213  </p>
   214  $(DDOC_MEMBERS
   215  $(SECTION データ型, $(SECBODY
   216  <p>
   217  以下のデータ型があります。
   218  </p>
   219  <ul>
   220    <li>整数:     <tt>0</tt>, <tt>123</tt>, <tt>456666666666666666666666666666666666666789</tt>, ...</li>
   221    <li>文字列:   <tt>"hello, world!"</tt>, ...</li>
   222    <li>関数:     <tt>fun(x){x+1}</tt></li>
   223    <li>テーブル: <tt>{car: 1, cdr: {car: 2, cdr: {}}}</tt></li>
   224    <li>ボトム:   (特殊なケースで作られます。「レイヤ」の説明参照のこと。)</li>
   225  </ul>
   226  <p>
   227  関数はいわゆる「クロージャ」です。静的スコープで外側の環境にアクセスできます。
   228  テーブルはいわゆるプロトタイプチェーンを持っていて、
   229  自分にないフィールドの場合は親に問い合わせが行く感じになっていますが、
   230  フィールドの書き換えがないので、これは特に意味ないかもしれない…。
   231  </p>
   232  <p>
   233  また、リストを扱うために、いわゆる「cons リスト」を使います。
   234  空リストを <tt>{}</tt>、1個以上要素があるものを <tt>{car: 先頭要素, cdr: 二番目以降のリスト}</tt>
   235  という形で。この形でリストを扱わなければならないという決まりはありませんが、
   236  この形は特別扱いされて <tt>print</tt> で綺麗に出力されたりします。
   237  </p>
   238  ))
   239  $(SECTION パターンマッチ, $(SECBODY
   240  <p>
   241  適当に実装されたパターンマッチがあります。
   242  リストの 2n 番目と 2n+1 番目を足して長さを半分にする関数:
   243  </p>
   244  <pre>
   245      def adjSum(lst)
   246      {
   247        case lst
   248          when {car:x, cdr:{car: y, cdr:z}}: {car: x+y, cdr: adjSum(z)}
   249          when {car:x, cdr:{}}: lst
   250          when {}: {}
   251      }
   252  </pre>
   253  <p>
   254  動かすときには、処理系がそれっぽい if-then-else に展開しています。
   255  <tt>when</tt> を上から試していって、最初にマッチしたところを実行します。
   256  どれにもマッチしないとエラーでプログラム終了します。
   257  </p>
   258  <pre>
   259     PAT ::= "_"                                      $(D_COMMENT # ワイルドカード)
   260           | ID                                       $(D_COMMENT # 変数パターン)
   261           | "{" ID ":" PAT "," ... "," ID : PAT "}"  $(D_COMMENT # テーブルパターン)
   262           | E                                        $(D_COMMENT # 値パターン)
   263  </pre>
   264  <p>
   265  変数パターンは常にマッチして、値をその変数に束縛します。
   266  ワイルドカードも常にマッチしますが、変数束縛しません。
   267  値パターンは、任意の式が書けます。その式を評価した結果と <tt>==</tt> ならマッチします。
   268  外で束縛された変数を値パターンとして配置、は直接はできないので
   269  </p>
   270  <pre>
   271     var x = 123;
   272     case foo
   273       when {val: x+0}: ... $(D_COMMENT # これは {val:123} と同じ)
   274       when {val: x}:   ... $(D_COMMENT # これは任意の foo.?val なら常にマッチ)
   275  </pre>
   276  <p>
   277  適当にちょっと複雑な式にしてやるとよいかも(裏技)。
   278  </p>
   279  <p>
   280  テーブルパターンは、書かれたキーが全てあればマッチします。
   281  <tt>{a: _}</tt> は、<tt>.a</tt> を持ってさえいればマッチするので、
   282  <tt>{a: 123, b: 456}</tt> なんかにもマッチします。
   283  なので、リストに対するパターンを書くときには、car/cdr の場合を先に書かないと
   284  <tt>when {}</tt> を上に書くと全部マッチしちゃいます。注意。
   285  </p>
   286  ))
   287  )
   288  ))
   289  
   290  
   291  
   292  
   293  
   294  $(SECTION Layers, $(SECBODY
   295  <p>
   296  この言語の唯一の特徴的な部分は、「レイヤ」機能です。
   297  </p>
   298  <p>
   299  ひとつのコードに複数の「意味」を持たせるのが、レイヤ機能の目的です。
   300  </p>
   301  $(DDOC_MEMBERS
   302  $(SECTION 概要, $(SECBODY
   303  <p>
   304  普通に Polemy のコードを動かすと、そのコードは「<tt>@value</tt> レイヤ」で動作します。
   305  インタプリタで実験。
   306  </p>
   307  <pre>
   308      $ bin/polemy
   309      Welcome to Polemy 0.1.0
   310      &gt;&gt; 1 + 2
   311      3
   312  </pre>
   313  この、普通に、数字の 1 は数字の 1 として、2 は 2 として、足し算は足し算として実行するのが、
   314  「<tt>@value</tt> レイヤ」です。
   315  レイヤを明示的に指定するには、<tt>レイヤ名( ... )</tt> という構文を使います。
   316  $(RED $(B レイヤ指定式)) と読んでいます。
   317  つまり、さっきのコードは以下のようにも書けます。
   318  <pre>
   319      &gt;&gt; @value( 1 + 2 )
   320      3
   321  </pre>
   322  他のレイヤで動かしてみましょう。適当に。「<tt>@hoge</tt> レイヤ」で。
   323  <pre>
   324      &gt;&gt; @hoge( 3 )
   325      polemy.failure.RuntimeException@polemy\eval.d(138):
   326      [<REPL>:4:8] lift function for @hoge is not registered
   327  </pre>
   328  <p>
   329  エラーになりました。Polemy のインタプリタは、起動時には、<tt>@value</tt>
   330  レイヤでのコードの意味しか知りません。<tt>@hoge</tt> レイヤでは <tt>3</tt>
   331  というのがどんな意味なのか、わかりません!というエラーが出ています。
   332  </p>
   333  <p>
   334  これを教えてあげるためには、<tt>@hoge</tt> レイヤの $(RED $(B リフト関数)) というものを定義します。
   335  </p>
   336  <pre>
   337      &gt;&gt; @@hoge = fun(x){ x*2 }
   338      (function:1bdc5c0:1ba8580)
   339  </pre>
   340  <p>
   341  <tt>@hoge</tt> レイヤでは、<tt>1</tt> というコードの意味は <tt>2</tt>、
   342  <tt>2</tt> というコードの意味は <tt>4</tt>、…、という、全部「2倍した意味」を持っていることにします。
   343  「<tt>@ レイヤ名 = ...</tt>」 という構文を使います。
   344  ここには、「<tt>@value</tt> レイヤでの値 <tt>x</tt> は <tt>@hoge</tt> レイヤではどういう意味になるか?」
   345  を計算して返す関数を登録します。
   346  これで、Polemy にも、<tt>@hoge</tt> レイヤの意味がわかるようになりました。
   347  </p>
   348  <pre>
   349      &gt;&gt; @hoge( 3 )
   350      6
   351  </pre>
   352  <p>
   353  では、1+2 を <tt>@hoge</tt> レイヤで動かしてみましょう。
   354  </p>
   355  <pre>
   356      &gt;&gt; @hoge( 1 + 2 )
   357      polemy.failure.RuntimeException@polemy\eval.d(466):
   358      [<REPL>:3:7] only @value layer can call native function: +
   359      [<REPL>:3:7] +
   360  </pre>
   361  <p>
   362  まだエラーですね。これは要するに "+" の意味がわからない、と言っています。
   363  $(RED $(B レイヤ指定変数定義式)) で、"+" の意味を教えてあげます。
   364  </p>
   365  <pre>
   366      &gt;&gt; @hoge + = fun(x, y) {x}
   367      (function:182eca0:18435e0)
   368      &gt;&gt; @hoge( 3 + 4 )
   369      6
   370  </pre>
   371  <p>
   372  できました。
   373  </p>
   374  <p>
   375  他の組み込み関数の意味も決めてみましょう。この <tt>@hoge</tt> レイヤでは、
   376  引き算のつもりで書いたコードが、掛け算になってしまうのだ!
   377  </p>
   378  <pre>
   379      &gt;&gt; @hoge - = fun(x, y) {x * y}
   380      (function:1b4c6a0:1b4fbe0)
   381      &gt;&gt; @hoge( 5 - 6 )
   382      polemy.failure.RuntimeException@polemy\eval.d(469):
   383      [<REPL>:3:24] only @value layer can call native function: *
   384      [<REPL>:3:24] *
   385      [<REPL>:4:8] -
   386  </pre>
   387  <p>
   388  5、の意味は 10 で 6 の意味は 12 なので、10 - 12 と見せかけて掛け算して 120 が返るのだ!
   389  と思いきや、エラーになってしまいました。なぜでしょう。それは、この "-" の定義、
   390  <code>fun(x, y) {x * y}</code> 自体が、<tt>@hoge</tt> レイヤで実行されるからです。
   391  掛け算はまだ定義していません。
   392  </p>
   393  <p>
   394  ここは、「普通の」意味の掛け算を使いたいのです。
   395  この部分については、<tt>@value</tt> レイヤで計算して欲しい。
   396  そんなときは、レイヤ指定式を使います。
   397  </p>
   398  <pre>
   399      &gt;&gt; @hoge - = fun(x, y) {$(B @value(@hoge(x) * @hoge(y)))}
   400      (function:1b086c0:1b4fbe0)
   401      &gt;&gt; @hoge( 5 - 6 )
   402      120
   403  </pre>
   404  <p>
   405  できました。掛け算は、<tt>@value</tt> レイヤの意味で実行します。
   406  各変数は、<tt>@hoge</tt> レイヤで計算された意味を使います、という意味になります。
   407  </p>
   408  ))
   409  $(SECTION 関数の自動リフト, $(SECBODY
   410  <p>
   411  続きです。ちょっと関数を定義してみました。
   412  </p>
   413  <pre>
   414      &gt;&gt; def twoMinus(x,y,z) { x - y - z }
   415      (function:1b26420:1b4fbe0)
   416      &gt;&gt; twoMinus(1,2,3)
   417      -4
   418  </pre>
   419  <p>
   420  <tt>@value</tt> レイヤで実行すると、当然、1 から 2 と 3 を引いて、-4 です。
   421  </p>
   422  <pre>
   423      &gt;&gt; @hoge( twoMinus(1,2,3) )
   424      48
   425  </pre>
   426  <p>
   427  <tt>@hoge</tt> レイヤだと、2 と 4 と 6 を掛け算するので、結果は 48 です。
   428  </p>
   429  <p>
   430  1, 2, 3 のような値と、+ や - のような組み込み関数については、
   431  「<tt>@hoge</tt> レイヤでの意味」をレイヤを定義する人が決めてやる必要があります。
   432  でも、それさえ決めれば、あとはプログラム中で自分で定義した関数はすべて、
   433  Polemy 側で自動的にそのレイヤでの意味で実行できるようになります。
   434  </p>
   435  <p>
   436  レイヤ指定変数定義を使って、変数の意味をそのレイヤでだけ上書きして、
   437  違う意味を与えてやっても構いません。
   438  </p>
   439  <pre>
   440      &gt;&gt; def twoMinus(x,y,z) { x - y - z } $(D_COMMENT # @value レイヤでの定義)
   441      &gt;&gt; @hoge twoMinus(x,y,z) { 21 }      $(D_COMMENT # @hoge レイヤでの定義)
   442      &gt;&gt; twoMinus(1,2,3)
   443      -4
   444      &gt;&gt; @hoge( twoMinus(1,2,3) )
   445      42
   446  </pre>
   447  <p>
   448  こんな感じで。
   449  </p>
   450  ))
   451  $(SECTION レイヤ指定引数, $(SECBODY
   452  <p>
   453  ここまでのサンプルでは、コードを書いた人が、レイヤ指定式で明示的にレイヤを切り替えていました。
   454  $(RED $(B レイヤ指定引数)) を使うと、ライブラリ関数などを書くときに、
   455  「この関数の第2引数は <tt>@hoge</tt> レイヤで計算して欲しい」
   456  といった指定ができます。
   457  </p>
   458  <pre>
   459      &gt;&gt; def f(x, y $(B @hoge)) { x + @hoge(y) }
   460      &gt;&gt; f(1, 2)
   461      5
   462  </pre>
   463  <p>
   464  f の第2引数は、必ず <tt>@hoge</tt> レイヤで解釈されます。
   465  </p>
   466  <pre>
   467      &gt;&gt; def ff(x, y $(B @hoge @value)) { x + @hoge(y) + @value(y) }
   468      &gt;&gt; ff(1, 2)
   469      7
   470  </pre>
   471  <p>
   472  <tt>@hoge</tt> と <tt>@value</tt> の両方のレイヤで解釈して欲しい、という欲張りな人は、
   473  レイヤ指定を複数並べて下さい。
   474  </p>
   475  <p>
   476  なにもレイヤ指定がないと、$(RED $(B ニュートラルレイヤ指定)) と呼ばれ、
   477  その関数の呼び出し側が解釈されていたレイヤと同じところにセットされます。
   478  <tt>let</tt>, <tt>var</tt>, <tt>def</tt> による変数定義も同じで、
   479  <tt>@hoge x = ...</tt> とレイヤを明示するとそのレイヤでの変数の意味が定義されますが、
   480  <tt>let x = ...</tt> とレイヤ指定しないで書くと、現在解釈中のレイヤに定義、という動作をします。
   481  </p>
   482  ))
   483  $(SECTION ボトムと自動メモ化, $(SECBODY
   484  <p>
   485  パターンマッチ失敗時と、"..." という式を実行したときと、再帰が無限に止まらなくなったとき、
   486  には、Polemy のコードは実行時エラーで終了します……<tt>@value</tt> レイヤならば。
   487  </p>
   488  <p>
   489  ユーザー定義レイヤでは、このような時にも実行時エラーにならず、
   490  「$(RED $(B ボトム))」という特別な値がリフト関数に渡されます。
   491  (ボトムのリフトに失敗した時は、この再帰停止処理は行われません。無限ループします。)
   492  組み込みの <tt>_isbot</tt> 関数で、ボトムかどうか判定できます。
   493  </p>
   494  <p>
   495  「再帰が無限に止まらなくなったとき」は、
   496  ある引数で呼び出された関数が、return するよりも前にまた同じ引数で呼び出されたら、
   497  ループしていると見なすことで判定しています。
   498  これを判定する実装の副作用として、ユーザー定義のレイヤでは、関数は全てメモ化されています。
   499  つまり、ある関数が2回同じ引数同じ環境で呼び出されたら、1回目の答えをキャッシュしておいて、
   500  2回目は計算をせずに即座にキャッシュをひいて答えを返します。
   501  </p>
   502  ))
   503  $(SECTION まとめ, $(SECBODY
   504  <p>
   505  まとめると、以下の機能があります。
   506  </p>
   507  <ul>
   508  	<li><tt>@@layer = fun(x) { ... } in ...</tt> で、
   509  		<tt>@value</tt> レイヤの値に別のレイヤでの意味を与えるリフト関数を定義</li>
   510  	<li><tt>@layer x = ... in ...</tt> で、そのレイヤでのその変数の意味を定義</li>
   511  	<li>どちらも let/var/def 式の特殊形なので、<tt>@@layer(x) { ... } in ...</tt> などの略記も可。</li>
   512  	<li>式の途中で @layer( ... ) と書くと、レイヤを明示的に切り替えられる</li>
   513  	<li>関数の仮引数に fun(x @layer){ ... } とレイヤを指定すると、
   514  		対応する実引数はそのレイヤで解釈される。</li>
   515  </ul>
   516  <p>
   517  </p>
   518  ))
   519  $(SECTION 例, $(SECBODY
   520  <p>
   521  具体的な「値」のかわりに、その「メタ情報」を取り出して、それが処理によってどう変化するか、
   522  といった情報を解析するのを主な用途として、この機能を作ってみました。
   523  プログラムでよく使われる代表的なメタ情報は、「型」です。
   524  サンプルとしては、sample/type.pmy をご覧下さい。以下、簡単な概略。
   525  </p>
   526  <pre>
   527      @@type = fun(x) {
   528         if( _isint(x) ) then "int"
   529         else if( _isstr(x) ) then "str"
   530         else if( _isbot(x) ) then "runtime error"
   531         else "type error"
   532      };
   533  </pre>
   534  <pre>
   535      &gt;&gt; @type( 1 )
   536      int
   537      &gt;&gt; @type( 2 )
   538      int
   539      &gt;&gt; @type( "foo" )
   540      str
   541  </pre>
   542  <p>
   543  こんな風に、値をメタ情報へ抽象化するのが、リフト関数です。
   544  </p>
   545  <p>
   546  型に抽象化したレイヤでの、組み込み関数の意味を考えましょう。
   547  "+" は、"int" と "int" を足したら "int" を返す関数です。
   548  それ以外なら"型エラー"を返します。そういう関数です。
   549  </p>
   550  <pre>
   551      var int_int_int = fun (x, y) {@value(
   552         var tx = @type(x);
   553         var ty = @type(y);
   554         if tx=="runtime error" then ty
   555         else if ty=="runtime error" then tx
   556         else if tx=="int" && ty=="int" then "int"
   557         else "type error"
   558      )};
   559  
   560      @type + = int_int_int;
   561      @type - = int_int_int;
   562      @type &lt; = int_int_int;
   563  </pre>
   564  <pre>
   565      &gt;&gt; @type( 1 + 2 )
   566      int
   567      &gt;&gt; @type( 1 + "foo" )
   568      type error
   569  </pre>
   570  <p>
   571  「実行時エラーについては、それが起きなければ返すはずの型」を計算するという定義に、
   572  ここではしています。さらに(ちょっと手抜きで int 以外を考えていない)if の型定義を考えると、
   573  こんな雰囲気。
   574  </p>
   575  <pre>
   576     @type if (c, t, e) {@value(
   577        if( @type(c)=="int" || @type(c)=="runtime error" ) then
   578           @type( int_int_int(t(), e()) )
   579        else
   580           "type error"
   581     )};
   582  </pre>
   583  <p>
   584  関数が自動リフトされるので、フィボナッチ関数の型を調べることができます。
   585  </p>
   586  <pre>
   587     &gt;&gt; def fib(x) { if x<2 then 1 else fib(x-1)+fib(x-2) };
   588     &gt;&gt; @type( fib(100000000000000) )
   589     int
   590     &gt;&gt; def gib(x) { if x<2 then 1 else gib(x-1)+gib(x-"str") };
   591     &gt;&gt; @type( gib(100000000000000) )
   592     type error
   593  </pre>
   594  <p>
   595  この定義で <tt>fib(100000000000000)</tt> を <tt>@value</tt> レイヤで普通に計算して、
   596  結果の型を見る、というのでは時間がいくらあっても足りません。
   597  いったん <tt>@type</tt> のメタ情報の世界に移ってから計算できるのが、レイヤ機能の肝です。
   598  </p>
   599  <p>
   600  正確には、この定義で <tt>@type</tt> レイヤに移ると fib("int") を無限に呼び出し続けて止まらなくなるのですが、
   601  そこは、自動メモ化による再帰検出でボトム値を返す機能によって、うまく止まっています。
   602  </p>
   603  <p>
   604  それでも上手く型計算ができない(あるいはすごく遅くなる)ような複雑な関数があるかもしれません。
   605  仕方がないので、型情報をアノテーションとしてつけてあげることも可能です。
   606  </p>
   607  <pre>
   608     @type f = int_int_int;
   609       def f(x,y) { ...とても型を計算できないくらい複雑な定義... };
   610  </pre>
   611  <p>
   612  これが、レイヤ指定変数定義の典型的な使い道です。
   613  </p>
   614  ))
   615  )
   616  ))
   617  
   618  
   619  $(SECTION Macro Layers, $(SECBODY
   620  <p>
   621  Polemy 言語組み込みのレイヤは <code>@value</code> と <code>@macro</code> の二つです。
   622  (内部的にはもういくつかありますが、ユーザから直接は使えません。)
   623  <code>@value</code> は、「普通に」普通のセマンティクスでプログラムを実行するレイヤでした。
   624  <code>@macro</code> は、実は、<code>@value</code> よりも前に実行されるレイヤで、
   625  「プログラムを実行するとその構文木を返す」というセマンティクスで動きます。
   626  </p>
   627  <p>
   628  動きとしてはこうです。
   629  </p>
   630  <ol>
   631  <li>関数呼び出し時(とトップレベル環境の実行開始時)に、
   632  	まず、<code>@macro</code> レイヤでコードを実行。</li>
   633  <li>返ってきた構文木を、その関数を呼び出したときのレイヤで実行。</li>
   634  </ol>
   635  <p>
   636  <code>@macro</code> レイヤも所詮ただのレイヤですので、
   637  上で説明した方法で <code>@macro</code> レイヤに関数などを登録しておくことで、
   638  構文木の生成をいじることが可能です。まさにマクロ。
   639  </p>
   640  
   641  $(DDOC_MEMBERS
   642  $(SECTION 概要, $(SECBODY
   643  <p>
   644  samples/macro.pmy にいくつか使い方サンプルが置いてありますので、詳しくはそちらをどうぞ。
   645  </p>
   646  <pre>
   647      &gt;&gt; @macro( twice(print("Hello")) )
   648      {
   649        pos: {lineno:1, column:9, filename:<REPL>},
   650       args: [ { pos: {lineno:1, column:15, filename:<REPL>},
   651                args: [{pos:{lineno:1, column:21, filename:<REPL>},
   652                         is:Str,
   653                       data:Hello}],
   654                  is: App,
   655                 fun: {pos:{lineno:1, column:15, filename:<REPL>}, is:Var, name:print}}
   656             ],
   657         is: App,
   658        fun: {pos:{lineno:1, column:9, filename:<REPL>}, is:Var, name:twice}
   659      }
   660  </pre>
   661  <p>
   662  詳細は気にしなくて構いませんが、とにかく、<tt>@macro</tt> レイヤでは、
   663  基本的には、コードを実行するとそのコードの構文木がでてきます。
   664  この挙動は <tt>@macro</tt> レイヤの変数をセットすることで、カスタマイズできます。
   665  </p>
   666  <pre>
   667      &gt;&gt; @macro twice(x) { x; x } in twice(print("Hello"))
   668      Hello
   669      Hello
   670      Hello
   671  </pre>
   672  <p>
   673  (3回出力されてますが、3個目は <tt>print(x)</tt> の返値は <tt>x</tt> なので、
   674  それがREPLによって印字されているだけです。)
   675  <tt>@macro</tt> レイヤで <tt>in</tt> 以降を実行すると、<tt>print("Hello")</tt> という式を表す構文木が作られ、
   676  それが <tt>twice</tt> 関数に渡されます。<tt>twice</tt> の中身も <tt>@macro</tt> レイヤで実行されるので、
   677  構文木を作ろうとしますが、変数 <tt>x</tt> には <tt>@macro</tt> レイヤで値が入っているので、
   678  その値を読み取って構文木を作成します。
   679  結果として、2回 <tt>print("Hello")</tt> する構文木が作られて、
   680  その後で、それが <tt>@value</tt> レイヤで実行されています。
   681  </p>
   682  <p>
   683  本当にベタに構文木を作るだけなので、変数名の衝突などなどは気にしません。「衛生的でない」マクロです。
   684  </p>
   685  <pre>
   686      @macro LetItBe(x, y) { var $(B it) = x; y };  $(D_COMMENT # y の中で変数 it が使える)
   687      print( LetItBe("myself",  "when I find " ~ $(B it) ~ " in times of trouble") );
   688  </pre>
   689  <p>
   690  変数名に気をつけるには、組み込み関数 <tt>gensym()</tt> を使って頑張って下さい。
   691  </p>
   692  ))
   693  $(SECTION レイヤ切り替え, $(SECBODY
   694  <p>
   695  他のレイヤ同様、<tt>@macro</tt> レイヤを実行中に <tt>@layer( ... )</tt> 構文を使うことで、
   696  別のレイヤでコードを動かすこともできます。よく使う例は、<tt>@value</tt>
   697  レイヤに移ることで構文木を普通に計算して色々プログラム的にいじる用途です。
   698  </p>
   699  <pre>
   700      @macro reverseArgs(e) {$(B @value)(
   701          def rev(xs, acc) {
   702            case xs when {car:x, cdr:xs}: rev(xs, {car:x, cdr:acc}) when {}: acc
   703          };
   704          case @macro(e)
   705            when {is:"App", fun:f, args:as}: {is:"App", fun:f, args:rev(as,{})}
   706            when e: e
   707      )};
   708      print( reverseArgs(1-2) ); $(D_COMMENT # 2-1 == 1)
   709  </pre>
   710  <p>
   711  <tt>reverseArgs</tt> は、関数呼び出しの構文木の、引数の順番を逆転する関数です。
   712  <tt>@macro(e)</tt> によってマクロレイヤにセットされている構文木引数を取り出し、
   713  それを <tt>@value</tt> レイヤによる普通の計算プログラムで操作しています。
   714  <tt>@macro(...)</tt> はいわゆる「準クオート (quasiquote)」、
   715  <tt>@value(...)</tt> は「逆クオート (unquote)」にちょっと近いかもしれません。
   716  </p>
   717  <p>
   718  <tt>@layer(...)</tt> だけでなく、関数のレイヤ指定引数なども同様に使うことができるので、
   719  一部の引数は <tt>@macro</tt>、一部の引数は <tt>@value</tt> レイヤで受け取る関数を書くなど、
   720  さらに色々面白いことが可能です。
   721  </p>
   722  ))
   723  $(SECTION 構文木の構造, $(SECBODY
   724  <p>
   725  構文木がどのようなテーブルで渡されてくるかについては、ソースドキュメントの
   726  <a href="http://www.kmonos.net/repos/polemy/doc/tip/doc/ast.html">polemy.ast</a>
   727  のページをご覧下さい。例えば変数名を表す <code>Var</code> クラスには、
   728  継承の分も合わせて
   729  <tt><a href="http://www.kmonos.net/repos/polemy/doc/tip/doc/failure.html">LexPosition</a> pos;</tt>
   730  と <tt>string name;</tt> の2つのメンバがあるので
   731  </p>
   732  <pre>
   733      { is:   "Var",
   734        pos:  {filename:"foo.pmy", lineno:123, column:45},
   735        name: "x" }
   736  </pre>
   737  <p>
   738  こんな感じのテーブルになります。
   739  クラス名が <tt>is</tt> フィールドに、メンバ変数はそのままの名前で入ります。
   740  配列メンバは cons リストになって入ってきます。
   741  自分で構文木を作る時は、<tt>pos</tt> フィールドだけは省略しても構いません。
   742  </p>
   743  ))
   744  $(SECTION 微妙なところ1, $(SECBODY
   745  <p>
   746  ここまで、<tt>@macro</tt> が本当にただの1レイヤと説明してきましたが、
   747  実はちょっとトリックが潜んでいます。
   748  </p>
   749  <pre>
   750      &gt;&gt; @macro twice(x) {x; x} in twice($(B @value)(print("Hello")))
   751      Hello
   752      Hello
   753      Hello
   754  </pre>
   755  <p>
   756  先ほどの例に <tt>@value</tt> を増やしたものですが、これでもやはり、Hello
   757  が2回 print されるようになります。これは本来はおかしな話で、<tt>print("Hello")</tt>
   758  は <tt>@value</tt> レイヤで実行されて値に落ちるはずなので、1回しか print されないはず。
   759  </p>
   760  <p>
   761  実は、Polemy の中では、<tt>@macro</tt> レイヤと <tt>(rawmacro)</tt>
   762  レイヤという二つの異なるマクロ用レイヤが動いています。
   763  </p>
   764  <ul>
   765  	<li><tt>(rawmacro)</tt> も <tt>@macro</tt> も、コードを動かすとその構文木を返す意味論。</li>
   766  	<li>ただし、<tt>(rawmacro)</tt> も <tt>@macro</tt> も、
   767  		<tt>@macro</tt> レイヤに値のセットされた変数をみつけたときは、
   768  		その変数という構文木を作るのではなく、変数の内容を展開。</li>
   769  	<li>また <tt>@macro</tt> は、
   770  		レイヤ指定式を見ると実行レイヤを切り替て、構文木生成モードをやめてしまう。</li>
   771  	<li><tt>(rawmacro)</tt> は、
   772  		レイヤ指定式を見ても実行レイヤを切り替えないで構文木にする。</li>
   773  </ul>
   774  <p>
   775  ユーザーから直接 <tt>(rawmacro)</tt> は呼べませんが、
   776  「関数やトップレベル実行開始前のマクロ処理は <tt>(rawmacro)</tt> で実行開始」
   777  「<tt>@macro</tt> レイヤ以外で呼び出した関数の仮引数に <tt>@macro</tt> がついていたら、
   778  その実引数は <tt>(rawmacro)</tt> で実行」
   779  という2つのタイミングで <tt>(rawmacro)</tt> が動き出します。
   780  <tt>(rawmacro)</tt> が <tt>@macro</tt> レイヤから変数を見つけてマクロし始める時に、
   781  そこで <tt>@macro</tt> に動作が移ります。
   782  </p>
   783  <p>
   784  こうなっているのは、全部がレイヤ指定式に反応する <tt>@macro</tt> の動作だと、
   785  レイヤを使ったプログラムが全て <tt>@value</tt> 実行時ではなく、
   786  マクロ展開の時点で動き始めてしまって、おかしなことになるためです。
   787  色々考えた結果、とりあえずこの中途半端な混合が具合がよいのではないかということになりました。
   788  </p>
   789  ))
   790  $(SECTION 微妙なところ2, $(SECBODY
   791  <p>
   792  「関数実行開始時に、まずマクロレイヤを実行」と書きましたが、この時、関数内関数まで辿りにいくので、
   793  何重にもネストした関数を使っていると、内側の関数は、何重にもマクロ展開が走ってしまいます。
   794  これはなにかおかしい気がしますね。Scheme などはどうなっているのか調べないと…。
   795  </p>
   796  ))
   797  $(SECTION 微妙なところ3, $(SECBODY
   798  <p>
   799  これはエラーになります。
   800  </p>
   801  <pre>
   802      &gt;&gt; let _ = (@macro twice(x) {x;x} in twice(print("Hello")))
   803      polemy.failure.RuntimeException@polemy\value.d(109):
   804      [<REPL>:2:35] 'twice' is not set in @value layer
   805  </pre>
   806  <p>
   807  どういうことかというと、<tt>@macro</tt> で定義したマクロはいつから使えるようになるかという話で、
   808  この <tt>@macro twice(x) {x;x} in ...</tt> の部分は <tt>@value</tt> レイヤの式なので、
   809  まずこの式全体のマクロ展開が終わったあとにしか実行されないのです。<tt>twice</tt>
   810  がマクロと見なされはじめるのは、<tt>@macro</tt> 実行が終わった後。
   811  なので、
   812  例えば <tt>twice(print("Hello"))</tt> の部分を無名関数にラップしてやれば、
   813  マクロ展開を遅らせられて、 ちゃんと実行ができます。
   814  </p>
   815  <p>
   816  これだと余りにも不便なので、関数のトップレベルの変数宣言式の列についてだけは、
   817  <tt>@macro</tt> と <tt>@value</tt> の評価を交互にインターリーブするようにしました。
   818  「関数やREPLのトップレベルの最初に宣言したマクロだけは、その関数内で即座に使える」わけです。
   819  これも Scheme の let-syntax などなどの動きを調べて勉強しないと…。
   820  </p>
   821  ))
   822  )
   823  ))
   824  
   825  
   826  $(SECTION Built-in Primitives, $(SECBODY
   827  <p>
   828  組み込み関数・変数の一覧。
   829  </p>
   830  $(DDOC_MEMBERS
   831  
   832  $(SECTION テーブル操作, $(SECBODY
   833    $(TABLE
   834      $(TR $(TH {}) $(TD ()) $(TD 空のテーブルを作る))
   835      $(TR $(TH .) $(TD (t, s)) $(TD テーブル t の名前 s のフィールドの値を取得。なければ <tt>undefined</tt>))
   836      $(TR $(TH .?) $(TD (t, s)) $(TD テーブル t に名前 s のフィールドがあれば 1、なければ 0))
   837      $(TR $(TH .=) $(TD (t, s, v)) $(TD テーブル t を親に持ち、名前 s のフィールドに v が入ったテーブルを作る))
   838    )
   839  ))
   840  <br />
   841  
   842  $(SECTION 制御フロー, $(SECBODY
   843    $(TABLE
   844      $(TR $(TH if) $(TD (n, ft, fe)) $(TD n が非 0 なら <tt>ft()</t>、0 なら <tt>fe()</tt> を実行))
   845    )
   846  ))
   847  <br />
   848  
   849  $(SECTION 演算, $(SECBODY
   850    $(TABLE
   851      $(TR $(TH +) $(TD (n, m)) $(TD 整数 n と整数 m を足して返す))
   852      $(TR $(TH -) $(TD (n, m)) $(TD 整数の引き算))
   853      $(TR $(TH *) $(TD (n, m)) $(TD 整数の掛け算))
   854      $(TR $(TH /) $(TD (n, m)) $(TD 整数の割り算))
   855      $(TR $(TH %) $(TD (n, m)) $(TD 整数の剰余))
   856      $(TR $(TH &amp;&amp;) $(TD (n, m)) $(TD 整数 n と m が両方非 0 なら 1、それ以外では 0))
   857      $(TR $(TH ||) $(TD (n, m)) $(TD 整数 n と m がどちらか非 0 なら 1、それ以外では 0))
   858      $(TR $(TH ~) $(TD (a, b)) $(TD a と b を文字列化して結合))
   859      $(TR $(TH &lt;) $(TD (a, b)) $(TD a と b を比較))
   860      $(TR $(TH &lt;=) $(TD (a, b)) $(TD a と b を比較))
   861      $(TR $(TH &gt;) $(TD (a, b)) $(TD a と b を比較))
   862      $(TR $(TH &gt;=) $(TD (a, b)) $(TD a と b を比較))
   863      $(TR $(TH ==) $(TD (a, b)) $(TD a と b を比較))
   864      $(TR $(TH !=) $(TD (a, b)) $(TD a と b を比較))
   865    )
   866  <p>
   867  注意点として、作者の趣味の問題で、<tt>&amp;&amp;</tt> と <tt>||</tt> は short-circuit 評価をしません。
   868  整数演算の種類が少ないのは、D 言語の std.bigint がビット演算などをサポートしてないためです。
   869  文字列が結合しかできないのは、単に手抜きです。
   870  </p>
   871  ))
   872  
   873  $(SECTION 外部とのやりとり, $(SECBODY
   874    $(TABLE
   875      $(TR $(TH print) $(TD (a)) $(TD a を文字列化標準出力に改行付きで表示して、a を返す))
   876      $(TR $(TH argv) $(TD ) $(TD スクリプトに渡された引数文字列のconsリスト))
   877      $(TR $(TH gensym) $(TD ()) $(TD エセgensym。変数名として他とかぶらなそうな文字列を返します))
   878      $(TR $(TH rand) $(TD (n)) $(TD 0 以上 n 未満の自然数を31bit以内でランダムに生成します))
   879    )
   880  ))
   881  <br />
   882  
   883  $(SECTION データ型判定, $(SECBODY
   884    $(TABLE
   885      $(TR $(TH _isint) $(TD (a)) $(TD a が整数なら 1、でなければ 0))
   886      $(TR $(TH _isstr) $(TD (a)) $(TD a が文字列なら 1、でなければ 0))
   887      $(TR $(TH _isfun) $(TD (a)) $(TD a が関数なら 1、でなければ 0))
   888      $(TR $(TH _istbl) $(TD (a)) $(TD a がテーブルなら 1、でなければ 0))
   889      $(TR $(TH _isbot) $(TD (a)) $(TD a が未定義値なら 1、でなければ 0))
   890    )
   891  ))
   892  )
   893  ))
   894  
   895  )
   896  Macros:
   897      TITLE=Polemy Reference Manual
   898      DOCFILENAME=index.html
   899      SECTION=$(DDOC_DECL $(DDOC_PSYMBOL $1)) $(DDOC_DECL_DD $2)
   900      SECBODY=$0