Artifact Content
Not logged in

Artifact a7325259b4f099520e37c7aefedc7ae005e8ba00


     1  Ddoc
     2  $(DDOC_AUTHORS k.inaba)
     3  $(DDOC_LICENSE NYSL 0.9982 (http://www.kmonos.net/nysl/))
     4  
     5  <p>
     6  このファイルは、言語仕様などの簡単な説明です。
     7  </p>
     8  <p>
     9  あとついでに、左のサイドバーの "Package" タブをクリックすると実装のソースのドキュメントが読めます。
    10  </p>
    11  
    12  $(DDOC_MEMBERS
    13  
    14  $(SECTION Syntax, $(SECBODY
    15  <p>
    16  文法について。
    17  字句解析がわりと適当なので、
    18  変数宣言の変数名のところに、数字を変数名として使えて参照できない変数が作れたり、
    19  予約語は予約語として解釈され得ないところでは普通に変数名として使えちゃったりして、
    20  偶にとんでもない見かけのソースが構文解析通りますが、気にしないで適当に使って下さい。
    21  </p>
    22  
    23  $(DDOC_MEMBERS
    24  
    25  $(SECTION 文字コード, $(SECBODY
    26  <p>
    27  UTF-8 のみ対応です。
    28  </p>
    29  ))
    30  
    31  $(SECTION コメント, $(SECBODY
    32  <p>
    33  行コメントは <tt>#</tt> から改行までです。
    34  </p>
    35  <p>
    36  ブロックコメントはありません。
    37  </p>
    38  ))
    39  
    40  $(SECTION BNF, $(SECBODY
    41  <pre>
    42   ID    ::= 適当に識別子っぽい文字列
    43   LAYER ::= "@" ID
    44  
    45   E ::=
    46     $(D_COMMENT # 変数宣言)
    47       | DECL "=" E (";"|"in") E
    48       | DECL "(" PARAMS ")" "{" E "}" (";"|"in") E
    49       | DECL "=" E
    50       | DECL "(" PARAMS ")" "{" E "}"
    51  
    52           where DECL ::= ("var"|"let"|"def"|LAYER) ID | "@" LAYER
    53  
    54     $(D_COMMENT # リテラル)
    55       | INTEGER                        $(D_COMMENT # 非負整数)
    56       | STRING                         $(D_COMMENT # "" でくくった文字列。\" と \\ は使える)
    57       | "{" ENTRYS "}"                 $(D_COMMENT # テーブル)
    58       | "fun" "(" PARAMS ")" "{" E "}" $(D_COMMENT # 無名関数)
    59       |  "λ" "(" PARAMS ")" "{" E "}" $(D_COMMENT # 無名関数)
    60  
    61     $(D_COMMENT # 関数呼び出し)
    62       | E "(" ARGS")"
    63  
    64           where    ARGS ::= E "," ... "," E
    65                  PARAMS ::= (ID|LAYER)+ "," ... "," (ID|LAYER)+
    66                  ENTRYS ::= ID ":" E    "," ... "," ID ":" E
    67  
    68     $(D_COMMENT # 演算子など)
    69       | "(" E ")"                 $(D_COMMENT # ただの括弧)
    70       | "..."                     $(D_COMMENT # これを実行するとdie)
    71       | E BINOP E                 $(D_COMMENT # 二項演算子いろいろ)
    72       | E "."  ID                 $(D_COMMENT # テーブルのフィールドアクセス)
    73       | E ".?" ID                 $(D_COMMENT # テーブルにフィールドがあるか否か)
    74       | E "{" ENTRYS "}"          $(D_COMMENT # テーブル拡張)
    75       | "if" E ("then"|":"|"then" ":") E
    76       | "if" E ("then"|":"|"then" ":") E "else" ":"? E
    77  
    78     $(D_COMMENT # パターンマッチ)
    79       | "case" E ("when" PATTERN ":" E )* 
    80  
    81           where PATTERN ::= 式がだいたいなんでも書ける気がする
    82  
    83     $(D_COMMENT # レイヤ指定実行)
    84       | LAYER "(" E ")"
    85  </pre>
    86  ))
    87  
    88  $(SECTION 糖衣構文, $(SECBODY
    89  <p>
    90  演算子というものはありません。内部的には全て関数呼び出し構文に書き換えられています。<tt>if</tt> もです。
    91  <br/>
    92  パターンマッチも全部 <tt>if</tt> と <tt>==</tt> と <tt>&amp;&amp;</tt> と
    93  <tt>.</tt> と <tt>.?</tt> を使った関数呼び出し式に書き換えられていますが、
    94  規則の詳細を説明するのが面倒なので適当に想像して下さい。
    95  他の書き換えはこんな感じです。
    96  </p>
    97  <pre>
    98      if E then E         ⇒ if( E, fun(){E}, fun(){} )
    99      if E then E else E  ⇒ if( E, fun(){E}, fun(){E} )
   100      E BINOP E           ⇒ BINOP(E, E)
   101      { ENTRIES }         ⇒ {}{ ENTRIES }
   102      {}                  ⇒ {}()
   103      E {ID:E, ...}       ⇒ .=(E, ID, E) { ... }
   104  </pre>
   105  <p>
   106  変数宣言に色々ありますが、<tt>let</tt> と <tt>var</tt> と <tt>def</tt> は同じ扱いで、
   107  <tt>in</tt> と <tt>;</tt> は同じ扱いです。つまり
   108  </p>
   109  <pre>
   110     let x = E in E
   111     var x = E in E
   112     def x = E in E
   113     let x = E ; E
   114     var x = E ; E
   115     def x = E ; E
   116  </pre>
   117  <p>
   118  以上のどれも同じ意味なので、なんとなく関数型っぽく書きたい気分の日は <tt>let in</tt> を、
   119  手続き型っぽく書きたい気分の日は <tt>var ;</tt> を使うとよいと思います。
   120  <tt>if then else</tt> も微妙にコロンがあったりなかったりバリエーションがありますが好みで使います。
   121  </p>
   122  <p>
   123  関数を宣言するときは、<tt>fun</tt> や <tt>λ</tt> を省略できます。
   124  以下の書き換えが行われます。
   125  </p>
   126  <pre>
   127     def f( ARGS ) { E }; E   ⇒   def f = fun(ARGS){E}; E
   128  </pre>
   129  <p>
   130  他に、もっと手続き型っぽくための書き換え色々
   131  </p>
   132  <pre>
   133     fun () { E; E; E      }   ⇒   fun () { let _ = E in let _ = E in E }
   134     fun () { var x = 100  }   ⇒   fun () { var x = 100; x }
   135     fun () { var x = 100; }   ⇒   fun () { var x = 100; x }
   136     fun () { }                ⇒   fun () { "(empty function body)" }
   137  </pre>
   138  <p>
   139  中身が空の関数に何を返させるかは適当です。今はとりあえず適当に文字列返してます。
   140  </p>
   141  ))
   142  
   143  $(SECTION 変数のスコープ規則, $(SECBODY
   144  <p>
   145  基本的には、let によって常識的な感じに変数のスコープがネストします。
   146  </p>
   147  <pre>
   148     let x=21 in let x=x+x in x    $(D_COMMENT # 42)
   149  </pre>
   150  <p>
   151  一方で、"let rec" のような特別な構文はありませんが、
   152  </p>
   153  <pre>
   154     let f = fun(x) { if x==0 then 1 else x*f(x-1) } in f(10)  $(D_COMMENT # 3628800)
   155  </pre>
   156  <p>
   157  再帰的な関数定義なども、おそらく意図されたとおりに動きます。
   158  内部の詳細は、諸般の事情により、
   159  マジカルで破壊的なスコープ規則になっているのですが、
   160  同名の変数を激しく重ねて使ったりしなければ、
   161  だいたい自然な動きをすると思います、たぶん、はい。
   162  </p>
   163  <p>
   164  ひとつだけ不可思議な動きをするのは、以下のケースです。
   165  </p>
   166  <pre>
   167     let x = 1 in
   168     let f = fun() {x} in
   169     let x = 2 in
   170        f()    $(D_COMMENT # 2!!)
   171  </pre>
   172  <p>
   173  let-in を縦にチェインしたときだけ、同名変数を破壊的に上書きします
   174  (再帰関数の定義が"うまく"いっているのはこの上書きのためです)。
   175  なんでこんなことになっているかというと、
   176  後で説明する「レイヤ」を使ったときに
   177  <tt>let foo = ... in @lay foo = ... in ...</tt>
   178  で他レイヤに重ね書きするためであります。
   179  </p>
   180  ))
   181  )
   182  ))
   183  
   184  
   185  
   186  
   187  $(SECTION Basic Features, $(SECBODY
   188  <p>
   189  特に特徴的でもない部分を簡単にまとめ。
   190  </p>
   191  <ul>
   192    <li>静的型システムはありません。</li>
   193    <li>"ほぼ" 純粋関数型言語です。変数やテーブルのフィールドの破壊的な書き換えはできません。<br/>
   194        ただし、組み込み関数(<tt>print</tt>)と、変数のスコープ規則のマジカルな片隅に副作用があります。</li>
   195  </ul>
   196  <p>
   197  静的型システムがないのは意図的ですが、破壊的代入がないのは、単に実装がめんどかっただけなので、
   198  今後何か増えるかもしれません。増えないかもしれません。
   199  </p>
   200  $(DDOC_MEMBERS
   201  $(SECTION データ型, $(SECBODY
   202  <p>
   203  以下のデータ型があります。
   204  </p>
   205  <ul>
   206    <li>整数:     <tt>0</tt>, <tt>123</tt>, <tt>456666666666666666666666666666666666666789</tt>, ...</li>
   207    <li>文字列:   <tt>"hello, world!"</tt>, ...</li>
   208    <li>関数:     <tt>fun(x){x+1}</tt></li>
   209    <li>テーブル: <tt>{car: 1, cdr: {car: 2, cdr: {}}}</tt></li>
   210    <li>未定義値: (特殊なケースで作られます。「レイヤ」の説明参照のこと。)</li>
   211  </ul>
   212  <p>
   213  関数はいわゆる「クロージャ」です。静的スコープで外側の環境にアクセスできます。
   214  テーブルはいわゆるプロトタイプチェーンを持っていて、
   215  自分にないフィールドの場合は親に問い合わせが行く感じになっていますが、
   216  フィールドの書き換えがないので、これは特に意味ないかもしれない…。
   217  </p>
   218  <p>
   219  また、リストを扱うために、いわゆる「cons リスト」を使います。
   220  空リストを <tt>{}</tt>、1個以上要素があるものを <tt>{car: 先頭要素, cdr: 二番目以降のリスト}</tt>
   221  という形で。この形でリストを扱わなければならないという決まりはありませんが、
   222  この形は特別扱いされて <tt>print</tt> で綺麗に出力されたりします。
   223  </p>
   224  ))
   225  $(SECTION パターンマッチ, $(SECBODY
   226  <p>
   227  適当に実装されたパターンマッチがあります。
   228  リストの 2n 番目と 2n+1 番目を足して長さを半分にする関数:
   229  </p>
   230  <pre>
   231      def adjSum(lst)
   232      {
   233        case lst
   234          when {car:x, cdr:{car: y, cdr:z}}: {car: x+y, cdr: adjSum(z)}
   235          when {car:x, cdr:{}}: lst
   236          when {}: {}
   237      }
   238  </pre>
   239  <p>
   240  動かすときには、処理系がそれっぽい if-then-else に展開しています。
   241  <tt>when</tt> を上から試していって、最初にマッチしたところを実行します。
   242  どれにもマッチしないとエラーでプログラム終了します。
   243  </p>
   244  <pre>
   245     PAT ::= "_"                                      $(D_COMMENT # ワイルドカード)
   246           | ID                                       $(D_COMMENT # 変数パターン)
   247           | "{" ID ":" PAT "," ... "," ID : PAT "}"  $(D_COMMENT # テーブルパターン)
   248           | E                                        $(D_COMMENT # 値パターン)
   249  </pre>
   250  <p>
   251  変数パターンは常にマッチして、値をその変数に束縛します。
   252  ワイルドカードも常にマッチしますが、変数束縛しません。
   253  値パターンは、任意の式が書けます。その式を評価した結果と <tt>==</tt> ならマッチします。
   254  外で束縛された変数を値パターンとして配置、は直接はできないので
   255  </p>
   256  <pre>
   257     var x = 123;
   258     case foo
   259       when {val: x+0}: ... $(D_COMMENT # これは {val:123} と同じ)
   260       when {val: x}:   ... $(D_COMMENT # これは任意の foo.?val なら常にマッチ)
   261  </pre>
   262  <p>
   263  適当にちょっと複雑な式にしてやるとよいかも(裏技)。
   264  </p>
   265  <p>
   266  テーブルパターンは、書かれたキーが全てあればマッチします。
   267  <tt>{a: _}</tt> は、<tt>.a</tt> を持ってさえいればマッチするので、
   268  <tt>{a: 123, b: 456}</tt> なんかにもマッチします。
   269  なので、リストに対するパターンを書くときには、car/cdr の場合を先に書かないと
   270  <tt>when {}</tt> を上に書くと全部マッチしちゃいます。注意。
   271  </p>
   272  ))
   273  )
   274  ))
   275  
   276  
   277  
   278  
   279  
   280  $(SECTION Layers, $(SECBODY
   281  <pre>
   282  [Layers :: Overview]
   283  
   284    Polemy's runtime environment has many "layer"s.
   285    Usual execution run in the @value layer.
   286  
   287      >> 1 + 2
   288      3
   289      >> @value( 1 + 2 )
   290      3
   291  
   292    Here you can see that @LayerName( Expression ) executes the inner Expression in
   293    the @LayerName layer. Other than @value, one other predefined layer exists: @macro.
   294  
   295      >> @macro( 1+2 )
   296      {pos@value:{lineno@value:3, column@value:9, filename@value:<REPL>},
   297        is@value:app,
   298      args@value:{car@value:{pos@value:{lineno@value:3, column@value:9, filename@value:<REPL>},
   299                              is@value:int,
   300                            data@value:1},
   301                  cdr@value:{
   302                    car@value:{pos@value:{lineno@value:3, column@value:11, filename@value:<REPL>},
   303                                is@value:int,
   304                              data@value:2},
   305                    cdr@value:{}}},
   306       fun@value:{pos@value:{lineno@value:3, column@value:10, filename@value:<REPL>},
   307                   is@value:var,
   308                 name@value:+}}
   309  
   310    (Sorry, this pretty printing is not available on the actual interpreter...)
   311    This evaluates the expression 1+2 in the @macro layer. In this layer, the meaning of
   312    the program is its abstract syntax tree.
   313  
   314    You can interleave layers.
   315    The root node of the abstract syntax tree is function "app"lication.
   316  
   317      >> @value(@macro( 1+2 ).is)
   318      app
   319  
   320  
   321  
   322  [Layers :: Defining a new layer]
   323  
   324    To define a new layer, you should first tell how to "lift" existing values two the new layer.
   325    Let us define the "@type" layer, where the meaning of programs is their static type.
   326  
   327      >> @@type = fun(x) {
   328      >>   if( _isint(x) ) { "int" } else {
   329      >>   if( _isfun(x) ) { x } else { "unknown" } }
   330      >> }
   331      (Note: polemy REPL may warn some exception here but please ignore)
   332  
   333    For simplicity, I here deal only with integers.
   334    _isint is a primitive function of Polemy that checks the dynamic type of a value.
   335    For function, leaving it untouched works well for almost all layers.
   336  
   337      >> @type( 1 )
   338      int
   339      >> @type( 2 )
   340      int
   341      >> @type( "foo" )
   342      unknown
   343  
   344    Fine! Let's try to type 1+2.
   345  
   346      >> @type( 1 + 2 )
   347      ...\value.d(119): [<REPL>:6:8] only @value layer can call native function
   348  
   349    Note that the behavior of this program is
   350      - run 1+2 in the @type layer
   351    and NOT
   352      - run 1+2 in @value and obtain 3 and run 3 in the @type.
   353    The problem is, the variable "+" is defined only in the @value layer.
   354    To carry out computation in the @type layer. We need to define it also
   355    in the @type layer.
   356  
   357    To define some variable in a specific layer, use @LayerName in place of
   358    (let|var|def)s.
   359  
   360      >> let x = 2
   361      >> @value x = 2
   362      >> @type x = "int"
   363      >> @hoge x = "fuga"
   364  
   365    For "+", do it like this.
   366  
   367      >> @type "+" = fun(x,y) {@value(
   368      >>   if( @type(x)=="int" && @type(y)=="int" ) { "int" } else { "typeerror" }
   369      >> )}
   370      polemy.value.native!(IntValue,IntValue,IntValue).native.__anonclass24
   371  
   372    It is just computing the return type from the input type.
   373    Not here that the intended "meaning" of if-then-else is the runtime-branching,
   374    and the meaning of "==" is the value-comparison. These are the @value layer
   375    behavior. So we have defined the function body inside @value layer.
   376    But when we refer the variables x and y, we need its @type layer meaning.
   377    Hence we use @type() there.
   378  
   379    Now we get it.
   380  
   381      >> @type( 1 + 2 )
   382      int
   383  
   384    Well, but do we have to define the @type layer meaning for every variables???
   385    No. After you defined @type "+", you'll automatically get the following:
   386  
   387      >> def double(x) { x + x }
   388      (function:17e4740:1789720)
   389  
   390      >> @type( double(123) )
   391      int
   392  
   393    Every user-defined functions are automatically "lift"ed to the appropriate layer.
   394    Only primitive functions like "+" requires @yourNewLayer annotation.
   395  
   396  
   397  
   398  [Layers :: neutral-layer]
   399  
   400    let|var|def is to define a variable in the "current" layer.
   401    Not necessary to the @value layer.
   402  
   403      >> @value( let x = 1 in @value(x) )
   404      1
   405  
   406      >> @macro( let x = 1 in @value(x) )
   407      polemy.failure.RuntimeException: [<REPL>:14:29] variable x not found
   408  
   409      >> @macro( let x = 1 in @macro(x) )
   410      {pos@value:{lineno@value:15, ...
   411  
   412  
   413  
   414  [Layers :: Layered-Parameters]
   415  
   416      >> def foo(x @macro @value) { {fst: x, snd: @macro(x)} }
   417      (function:1730360:1789720)
   418  
   419    If you annotate function parameters by @LayerNames, when you invoke the function...
   420  
   421      >> foo(1+2)
   422      {snd@value: {pos@value:{lineno@value:17, column@value:5, filename@value:<REPL>},
   423                    is@value:app, arg@value:{...
   424      /fst@value:3
   425      /}
   426  
   427    its corresponding arguments are evaluated in the layer and passed to it.
   428    If you specify multiple layers, the argument expression is run multiple times.
   429    If you do not specify any layer for a parameter, it works in the neutral layer.
   430  </pre>
   431  ))
   432  
   433  
   434  $(SECTION Macro Layers, $(SECBODY
   435  <p>
   436  Polemy 言語組み込みのレイヤは <code>@value</code> と <code>@macro</code> の二つです。
   437  (内部的にはもういくつかありますが、ユーザから直接は使えません。)
   438  <code>@value</code> は、「普通に」普通のセマンティクスでプログラムを実行するレイヤでした。
   439  <code>@macro</code> は、実は、<code>@value</code> よりも前に実行されるレイヤで、
   440  「プログラムを実行するとその構文木を返す」というセマンティクスで動きます。
   441  </p>
   442  <pre>
   443      (ここに例)
   444  </pre>
   445  <p>
   446  動きとしてはこうです。
   447  </p>
   448  <ol>
   449  <li>関数呼び出し時(とトップレベル環境の実行開始時)に、
   450  	まず、<code>@macro</code> レイヤでコードを実行。</li>
   451  <li>返ってきた構文木を、<code>@value</code> レイヤ、
   452  	またはその関数を呼び出したときのレイヤで実行。</li>
   453  </ol>
   454  <p>
   455  <code>@macro</code> レイヤも所詮ただのレイヤですので、
   456  上で説明した方法で <code>@macro</code> レイヤに関数などを登録しておくことで、
   457  構文木の生成をいじることが可能です。まさにマクロ。
   458  </p>
   459  
   460  $(DDOC_MEMBERS
   461  $(SECTION 概要, $(SECBODY
   462  <p>
   463  samples/macro.pmy にいくつか使い方サンプルが置いてありますので、詳しくはそちらをどうぞ。
   464  </p>
   465  <pre>
   466      &gt;&gt; @macro( twice(print("Hello")) )
   467      {
   468        pos: {lineno:1, column:9, filename:<REPL>},
   469       args: [ { pos: {lineno:1, column:15, filename:<REPL>},
   470                args: [{pos:{lineno:1, column:21, filename:<REPL>},
   471                         is:Str,
   472                       data:Hello}],
   473                  is: App,
   474                 fun: {pos:{lineno:1, column:15, filename:<REPL>}, is:Var, name:print}}
   475             ],
   476         is: App,
   477        fun: {pos:{lineno:1, column:9, filename:<REPL>}, is:Var, name:twice}
   478      }
   479  </pre>
   480  <p>
   481  詳細は気にしなくて構いませんが、とにかく、<tt>@macro</tt> レイヤでは、
   482  基本的には、コードを実行するとそのコードの構文木がでてきます。
   483  この挙動は <tt>@macro</tt> レイヤの変数をセットすることで、カスタマイズできます。
   484  </p>
   485  <pre>
   486      &gt;&gt; @macro twice(x) { x; x } in twice(print("Hello"))
   487      Hello
   488      Hello
   489      Hello
   490  </pre>
   491  <p>
   492  (3回出力されてますが、3個目は <tt>print(x)</tt> の返値は <tt>x</tt> なので、
   493  それがREPLによって印字されているだけです。)
   494  <tt>@macro</tt> レイヤで <tt>in</tt> 以降を実行すると、<tt>print("Hello")</tt> という式を表す構文木が作られ、
   495  それが <tt>twice</tt> 関数に渡されます。<tt>twice</tt> の中身も <tt>@macro</tt> レイヤで実行されるので、
   496  構文木を作ろうとしますが、変数 <tt>x</tt> には <tt>@macro</tt> レイヤで値が入っているので、
   497  その値を読み取って構文木を作成します。
   498  結果として、2回 <tt>print("Hello")</tt> する構文木が作られて、
   499  その後で、それが <tt>@value</tt> レイヤで実行されています。
   500  </p>
   501  <p>
   502  本当にベタに構文木を作るだけなので、変数名の衝突などなどは気にしません。「衛生的でない」マクロです。
   503  </p>
   504  <pre>
   505      @macro LetItBe(x, y) { var $(B it) = x; y };  $(D_COMMENT # y の中で変数 it が使える)
   506      print( LetItBe("myself",  "when I find " ~ $(B it) ~ " in times of trouble") );
   507  </pre>
   508  <p>
   509  変数名に気をつけるには、組み込み関数 <tt>gensym()</tt> を使って頑張って下さい。
   510  </p>
   511  ))
   512  $(SECTION レイヤ切り替え, $(SECBODY
   513  <p>
   514  他のレイヤ同様、<tt>@macro</tt> レイヤを実行中に <tt>@layer( ... )</tt> 構文を使うことで、
   515  別のレイヤでコードを動かすこともできます。よく使う例は、<tt>@value</tt>
   516  レイヤに移ることで構文木を普通に計算して色々プログラム的にいじる用途です。
   517  </p>
   518  <pre>
   519      @macro reverseArgs(e) {$(B @value)(
   520          def rev(xs, acc) {
   521            case xs when {car:x, cdr:xs}: rev(xs, {car:x, cdr:acc}) when {}: acc
   522          };
   523          case @macro(e)
   524            when {is:"App", fun:f, args:as}: {is:"App", fun:f, args:rev(as,{})}
   525            when e: e
   526      )};
   527      print( reverseArgs(1-2) ); $(D_COMMENT # 2-1 == 1)
   528  </pre>
   529  <p>
   530  <tt>reverseArgs</tt> は、関数呼び出しの構文木の、引数の順番を逆転する関数です。
   531  <tt>@macro(e)</tt> によってマクロレイヤにセットされている構文木引数を取り出し、
   532  それを <tt>@value</tt> レイヤによる普通の計算プログラムで操作しています。
   533  要は、<tt>@macro(...)</tt> はいわゆる「準クオート (quasiquote)」、
   534  <tt>@value(...)</tt> は「逆クオート (unquote)」に近い働きをします。
   535  </p>
   536  <p>
   537  <tt>@layer(...)</tt> だけでなく、関数のレイヤ指定引数なども同様に使うことができるので、
   538  一部の引数は <tt>@macro</tt>、一部の引数は <tt>@value</tt> レイヤで受け取る関数を書くなど、
   539  さらに色々面白いことが可能です。
   540  </p>
   541  ))
   542  $(SECTION 構文木の構造, $(SECBODY
   543  <p>
   544  構文木がどのようなテーブルで渡されてくるかについては、ソースドキュメントの
   545  <a href="http://www.kmonos.net/repos/polemy/doc/tip/doc/ast.html">polemy.ast</a>
   546  のページをご覧下さい。例えば変数名を表す <code>Var</code> クラスには、
   547  継承の分も合わせて
   548  <tt><a href="http://www.kmonos.net/repos/polemy/doc/tip/doc/failure.html">LexPosition</a> pos;</tt>
   549  と <tt>string name;</tt> の2つのメンバがあるので
   550  </p>
   551  <pre>
   552      { is:   "Var",
   553        pos:  {filename:"foo.pmy", lineno:123, column:45},
   554        name: "x" }
   555  </pre>
   556  <p>
   557  こんな感じのテーブルになります。
   558  クラス名が <tt>is</tt> フィールドに、メンバ変数はそのままの名前で入ります。
   559  配列メンバは cons リストになって入ってきます。
   560  自分で構文木を作る時は、<tt>pos</tt> フィールドだけは省略しても構いません。
   561  </p>
   562  ))
   563  $(SECTION 微妙なところ, $(SECBODY
   564  <p>
   565  ここまで、<tt>@macro</tt> が本当にただの1レイヤであるかのように説明してきましたが、
   566  実はちょっと幾つかのトリックが潜んでいます。
   567  </p>
   568  <pre>
   569      &gt;&gt; @macro twice(x) {x; x} in twice($(B @value)(print("Hello")))
   570      Hello
   571      Hello
   572      Hello
   573  </pre>
   574  <p>
   575  先ほどの例に <tt>@value</tt> を増やしたものですが、これでもやはり、Hello
   576  が2回 print されるようになります。
   577  </p>
   578  <pre>
   579  <tt>@macro</tt> レイヤと <tt>(rawmacro)</tt> レイヤという二つが協調して動作しています。
   580     (rawmacro) レイヤの話
   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 "y"
   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 startup.
   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).
   607  </pre>
   608  ))
   609  )
   610  ))
   611  
   612  
   613  $(SECTION Built-in Primitives, $(SECBODY
   614  <p>
   615  組み込み関数・変数の一覧。
   616  </p>
   617  $(DDOC_MEMBERS
   618  
   619  $(SECTION テーブル操作, $(SECBODY
   620    $(TABLE
   621      $(TR $(TH {}) $(TD ()) $(TD 空のテーブルを作る))
   622      $(TR $(TH .) $(TD (t, s)) $(TD テーブル t の名前 s のフィールドの値を取得。なければ <tt>undefined</tt>))
   623      $(TR $(TH .?) $(TD (t, s)) $(TD テーブル t に名前 s のフィールドがあれば 1、なければ 0))
   624      $(TR $(TH .=) $(TD (t, s, v)) $(TD テーブル t を親に持ち、名前 s のフィールドに v が入ったテーブルを作る))
   625    )
   626  ))
   627  <br />
   628  
   629  $(SECTION 制御フロー, $(SECBODY
   630    $(TABLE
   631      $(TR $(TH if) $(TD (n, ft, fe)) $(TD n が非 0 なら <tt>ft()</t>、0 なら <tt>fe()</tt> を実行))
   632    )
   633  ))
   634  <br />
   635  
   636  $(SECTION 演算, $(SECBODY
   637    $(TABLE
   638      $(TR $(TH +) $(TD (n, m)) $(TD 整数 n と整数 m を足して返す))
   639      $(TR $(TH -) $(TD (n, m)) $(TD 整数の引き算))
   640      $(TR $(TH *) $(TD (n, m)) $(TD 整数の掛け算))
   641      $(TR $(TH /) $(TD (n, m)) $(TD 整数の割り算))
   642      $(TR $(TH %) $(TD (n, m)) $(TD 整数の剰余))
   643      $(TR $(TH &amp;&amp;) $(TD (n, m)) $(TD 整数 n と m が両方非 0 なら 1、それ以外では 0))
   644      $(TR $(TH ||) $(TD (n, m)) $(TD 整数 n と m がどちらか非 0 なら 1、それ以外では 0))
   645      $(TR $(TH ~) $(TD (a, b)) $(TD a と b を文字列化して結合))
   646      $(TR $(TH &lt;) $(TD (a, b)) $(TD a と b を比較))
   647      $(TR $(TH &lt;=) $(TD (a, b)) $(TD a と b を比較))
   648      $(TR $(TH &gt;) $(TD (a, b)) $(TD a と b を比較))
   649      $(TR $(TH &gt;=) $(TD (a, b)) $(TD a と b を比較))
   650      $(TR $(TH ==) $(TD (a, b)) $(TD a と b を比較))
   651      $(TR $(TH !=) $(TD (a, b)) $(TD a と b を比較))
   652    )
   653  <p>
   654  注意点として、作者の趣味の問題で、<tt>&amp;&amp;</tt> と <tt>||</tt> は short-circuit 評価をしません。
   655  整数演算の種類が少ないのは、D 言語の std.bigint がビット演算などをサポートしてないためです。
   656  文字列が結合しかできないのは、単に手抜きです。
   657  </p>
   658  ))
   659  
   660  $(SECTION 外部とのやりとり, $(SECBODY
   661    $(TABLE
   662      $(TR $(TH print) $(TD (a)) $(TD a を文字列化標準出力に改行付きで表示して、a を返す))
   663      $(TR $(TH argv) $(TD ) $(TD スクリプトに渡された引数文字列のconsリスト))
   664      $(TR $(TH gensym) $(TD ()) $(TD エセgensym。変数名として他とかぶらなそうな文字列を返します))
   665      $(TR $(TH rand) $(TD (n)) $(TD 0 以上 n 未満の自然数を31bit以内でランダムに生成します))
   666    )
   667  ))
   668  <br />
   669  
   670  $(SECTION データ型判定, $(SECBODY
   671    $(TABLE
   672      $(TR $(TH _isint) $(TD (a)) $(TD a が整数なら 1、でなければ 0))
   673      $(TR $(TH _isstr) $(TD (a)) $(TD a が文字列なら 1、でなければ 0))
   674      $(TR $(TH _isfun) $(TD (a)) $(TD a が関数なら 1、でなければ 0))
   675      $(TR $(TH _istable) $(TD (a)) $(TD a がテーブルなら 1、でなければ 0))
   676      $(TR $(TH _isundefined) $(TD (a)) $(TD a が未定義値なら 1、でなければ 0))
   677    )
   678  ))
   679  )
   680  ))
   681  
   682  )
   683  Macros:
   684      TITLE=Polemy Reference Manual
   685      DOCFILENAME=index.html
   686      SECTION=$(DDOC_DECL $(DDOC_PSYMBOL $1)) $(DDOC_DECL_DD $2)
   687      SECBODY=$0