Artifact Content
Not logged in

Artifact caf492581281c25dbc3fd7ad5bafdbc2f5f61f09


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