Artifact Content
Not logged in

Artifact b4c241e12eddc95c664dbcd8246545db82194781


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