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>&&</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 &&) $(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 <) $(TD (a, b)) $(TD a と b を比較))
588 $(TR $(TH <=) $(TD (a, b)) $(TD a と b を比較))
589 $(TR $(TH >) $(TD (a, b)) $(TD a と b を比較))
590 $(TR $(TH >=) $(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>&&</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