20be503cae 2010-11-24 kinaba: Ddoc 20be503cae 2010-11-24 kinaba: $(DDOC_AUTHORS k.inaba) 20be503cae 2010-11-24 kinaba: $(DDOC_LICENSE NYSL 0.9982 (http://www.kmonos.net/nysl/)) 20be503cae 2010-11-24 kinaba: 20be503cae 2010-11-24 kinaba: <p> 203e4cb208 2010-11-27 kinaba: 左のサイドバーの "Package" タブをクリックすると実装のソースのドキュメントが読めます。 20be503cae 2010-11-24 kinaba: </p> 20be503cae 2010-11-24 kinaba: <p> 203e4cb208 2010-11-27 kinaba: このファイルは、言語仕様などの、やや辞書的な説明です。<br /> 203e4cb208 2010-11-27 kinaba: もっとざっくりとした、言語デザインの方向性の魂的なものについては、 203e4cb208 2010-11-27 kinaba: 「メタプログラミングの会」の発表スライドをご覧下さい。 203e4cb208 2010-11-27 kinaba: </p> 203e4cb208 2010-11-27 kinaba: <p> 203e4cb208 2010-11-27 kinaba: あと、 やたらとマクロの章が長くなっていますが、 この部分は、 203e4cb208 2010-11-27 kinaba: レイヤ機能を入れたら自動的にすごく自然にマクロが入るなーと思って、 203e4cb208 2010-11-27 kinaba: おまけで実装してみた程度のものです。 203e4cb208 2010-11-27 kinaba: あんまり重要ではないので、適当にスルーして下さいませ。 203e4cb208 2010-11-27 kinaba: 単に、適当に入れたら適当で微妙な部分が多く残ってしまったので注意書きが増えているだけで…。 20be503cae 2010-11-24 kinaba: </p> 20be503cae 2010-11-24 kinaba: 20be503cae 2010-11-24 kinaba: $(DDOC_MEMBERS 20be503cae 2010-11-24 kinaba: 20be503cae 2010-11-24 kinaba: $(SECTION Syntax, $(SECBODY 20be503cae 2010-11-24 kinaba: <p> 20be503cae 2010-11-24 kinaba: 文法について。 20be503cae 2010-11-24 kinaba: 字句解析がわりと適当なので、 20be503cae 2010-11-24 kinaba: 変数宣言の変数名のところに、数字を変数名として使えて参照できない変数が作れたり、 20be503cae 2010-11-24 kinaba: 予約語は予約語として解釈され得ないところでは普通に変数名として使えちゃったりして、 20be503cae 2010-11-24 kinaba: 偶にとんでもない見かけのソースが構文解析通りますが、気にしないで適当に使って下さい。 20be503cae 2010-11-24 kinaba: </p> 20be503cae 2010-11-24 kinaba: 20be503cae 2010-11-24 kinaba: $(DDOC_MEMBERS 20be503cae 2010-11-24 kinaba: 20be503cae 2010-11-24 kinaba: $(SECTION 文字コード, $(SECBODY 20be503cae 2010-11-24 kinaba: <p> 20be503cae 2010-11-24 kinaba: UTF-8 のみ対応です。 20be503cae 2010-11-24 kinaba: </p> 20be503cae 2010-11-24 kinaba: )) 20be503cae 2010-11-24 kinaba: 20be503cae 2010-11-24 kinaba: $(SECTION コメント, $(SECBODY 20be503cae 2010-11-24 kinaba: <p> 20be503cae 2010-11-24 kinaba: 行コメントは <tt>#</tt> から改行までです。 20be503cae 2010-11-24 kinaba: </p> 20be503cae 2010-11-24 kinaba: <p> 20be503cae 2010-11-24 kinaba: ブロックコメントはありません。 20be503cae 2010-11-24 kinaba: </p> 20be503cae 2010-11-24 kinaba: )) 20be503cae 2010-11-24 kinaba: 20be503cae 2010-11-24 kinaba: $(SECTION BNF, $(SECBODY 20be503cae 2010-11-24 kinaba: <pre> 20be503cae 2010-11-24 kinaba: ID ::= 適当に識別子っぽい文字列 20be503cae 2010-11-24 kinaba: LAYER ::= "@" ID 20be503cae 2010-11-24 kinaba: 20be503cae 2010-11-24 kinaba: E ::= 20be503cae 2010-11-24 kinaba: $(D_COMMENT # 変数宣言) f7e9e77316 2010-11-26 kinaba: | DECL "=" E (";"|"in") E f7e9e77316 2010-11-26 kinaba: | DECL "(" PARAMS ")" "{" E "}" (";"|"in") E f7e9e77316 2010-11-26 kinaba: | DECL "=" E f7e9e77316 2010-11-26 kinaba: | DECL "(" PARAMS ")" "{" E "}" f7e9e77316 2010-11-26 kinaba: f7e9e77316 2010-11-26 kinaba: where DECL ::= ("var"|"let"|"def"|LAYER) ID | "@" LAYER 20be503cae 2010-11-24 kinaba: 20be503cae 2010-11-24 kinaba: $(D_COMMENT # リテラル) 20be503cae 2010-11-24 kinaba: | INTEGER $(D_COMMENT # 非負整数) 20be503cae 2010-11-24 kinaba: | STRING $(D_COMMENT # "" でくくった文字列。\" と \\ は使える) 20be503cae 2010-11-24 kinaba: | "{" ENTRYS "}" $(D_COMMENT # テーブル) 20be503cae 2010-11-24 kinaba: | "fun" "(" PARAMS ")" "{" E "}" $(D_COMMENT # 無名関数) 20be503cae 2010-11-24 kinaba: | "λ" "(" PARAMS ")" "{" E "}" $(D_COMMENT # 無名関数) 20be503cae 2010-11-24 kinaba: 20be503cae 2010-11-24 kinaba: $(D_COMMENT # 関数呼び出し) 20be503cae 2010-11-24 kinaba: | E "(" ARGS")" 20be503cae 2010-11-24 kinaba: 20be503cae 2010-11-24 kinaba: where ARGS ::= E "," ... "," E 20be503cae 2010-11-24 kinaba: PARAMS ::= (ID|LAYER)+ "," ... "," (ID|LAYER)+ 20be503cae 2010-11-24 kinaba: ENTRYS ::= ID ":" E "," ... "," ID ":" E 20be503cae 2010-11-24 kinaba: 20be503cae 2010-11-24 kinaba: $(D_COMMENT # 演算子など) 20be503cae 2010-11-24 kinaba: | "(" E ")" $(D_COMMENT # ただの括弧) f7e9e77316 2010-11-26 kinaba: | "..." $(D_COMMENT # これを実行するとdie) 20be503cae 2010-11-24 kinaba: | E BINOP E $(D_COMMENT # 二項演算子いろいろ) 20be503cae 2010-11-24 kinaba: | E "." ID $(D_COMMENT # テーブルのフィールドアクセス) 20be503cae 2010-11-24 kinaba: | E ".?" ID $(D_COMMENT # テーブルにフィールドがあるか否か) 20be503cae 2010-11-24 kinaba: | E "{" ENTRYS "}" $(D_COMMENT # テーブル拡張) 3ae09b8cbf 2010-11-24 kinaba: | "if" E ("then"|":"|"then" ":") E 3ae09b8cbf 2010-11-24 kinaba: | "if" E ("then"|":"|"then" ":") E "else" ":"? E 20be503cae 2010-11-24 kinaba: 20be503cae 2010-11-24 kinaba: $(D_COMMENT # パターンマッチ) 3ae09b8cbf 2010-11-24 kinaba: | "case" E ("when" PATTERN ":" E )* 20be503cae 2010-11-24 kinaba: 20be503cae 2010-11-24 kinaba: where PATTERN ::= 式がだいたいなんでも書ける気がする 20be503cae 2010-11-24 kinaba: 20be503cae 2010-11-24 kinaba: $(D_COMMENT # レイヤ指定実行) 20be503cae 2010-11-24 kinaba: | LAYER "(" E ")" 20be503cae 2010-11-24 kinaba: </pre> 20be503cae 2010-11-24 kinaba: )) 20be503cae 2010-11-24 kinaba: 20be503cae 2010-11-24 kinaba: $(SECTION 糖衣構文, $(SECBODY 20be503cae 2010-11-24 kinaba: <p> 20be503cae 2010-11-24 kinaba: 演算子というものはありません。内部的には全て関数呼び出し構文に書き換えられています。<tt>if</tt> もです。 20be503cae 2010-11-24 kinaba: <br/> 20be503cae 2010-11-24 kinaba: パターンマッチも全部 <tt>if</tt> と <tt>==</tt> と <tt>&&</tt> と 20be503cae 2010-11-24 kinaba: <tt>.</tt> と <tt>.?</tt> を使った関数呼び出し式に書き換えられていますが、 20be503cae 2010-11-24 kinaba: 規則の詳細を説明するのが面倒なので適当に想像して下さい。 20be503cae 2010-11-24 kinaba: 他の書き換えはこんな感じです。 20be503cae 2010-11-24 kinaba: </p> 20be503cae 2010-11-24 kinaba: <pre> 3ae09b8cbf 2010-11-24 kinaba: if E then E ⇒ if( E, fun(){E}, fun(){} ) 3ae09b8cbf 2010-11-24 kinaba: if E then E else E ⇒ if( E, fun(){E}, fun(){E} ) 8caee17864 2010-11-24 kinaba: E BINOP E ⇒ BINOP(E, E) 8caee17864 2010-11-24 kinaba: { ENTRIES } ⇒ {}{ ENTRIES } 8caee17864 2010-11-24 kinaba: {} ⇒ {}() 8caee17864 2010-11-24 kinaba: E {ID:E, ...} ⇒ .=(E, ID, E) { ... } 20be503cae 2010-11-24 kinaba: </pre> 20be503cae 2010-11-24 kinaba: <p> 20be503cae 2010-11-24 kinaba: 変数宣言に色々ありますが、<tt>let</tt> と <tt>var</tt> と <tt>def</tt> は同じ扱いで、 20be503cae 2010-11-24 kinaba: <tt>in</tt> と <tt>;</tt> は同じ扱いです。つまり 20be503cae 2010-11-24 kinaba: </p> 20be503cae 2010-11-24 kinaba: <pre> 20be503cae 2010-11-24 kinaba: let x = E in E 20be503cae 2010-11-24 kinaba: var x = E in E 20be503cae 2010-11-24 kinaba: def x = E in E 20be503cae 2010-11-24 kinaba: let x = E ; E 20be503cae 2010-11-24 kinaba: var x = E ; E 20be503cae 2010-11-24 kinaba: def x = E ; E 20be503cae 2010-11-24 kinaba: </pre> 20be503cae 2010-11-24 kinaba: <p> 20be503cae 2010-11-24 kinaba: 以上のどれも同じ意味なので、なんとなく関数型っぽく書きたい気分の日は <tt>let in</tt> を、 3ae09b8cbf 2010-11-24 kinaba: 手続き型っぽく書きたい気分の日は <tt>var ;</tt> を使うとよいと思います。 3ae09b8cbf 2010-11-24 kinaba: <tt>if then else</tt> も微妙にコロンがあったりなかったりバリエーションがありますが好みで使います。 20be503cae 2010-11-24 kinaba: </p> 20be503cae 2010-11-24 kinaba: <p> 20be503cae 2010-11-24 kinaba: 関数を宣言するときは、<tt>fun</tt> や <tt>λ</tt> を省略できます。 20be503cae 2010-11-24 kinaba: 以下の書き換えが行われます。 20be503cae 2010-11-24 kinaba: </p> 20be503cae 2010-11-24 kinaba: <pre> 20be503cae 2010-11-24 kinaba: def f( ARGS ) { E }; E ⇒ def f = fun(ARGS){E}; E 20be503cae 2010-11-24 kinaba: </pre> 20be503cae 2010-11-24 kinaba: <p> 20be503cae 2010-11-24 kinaba: 他に、もっと手続き型っぽくための書き換え色々 20be503cae 2010-11-24 kinaba: </p> 20be503cae 2010-11-24 kinaba: <pre> 20be503cae 2010-11-24 kinaba: fun () { E; E; E } ⇒ fun () { let _ = E in let _ = E in E } 20be503cae 2010-11-24 kinaba: fun () { var x = 100 } ⇒ fun () { var x = 100; x } 20be503cae 2010-11-24 kinaba: fun () { var x = 100; } ⇒ fun () { var x = 100; x } 20be503cae 2010-11-24 kinaba: fun () { } ⇒ fun () { "(empty function body)" } 20be503cae 2010-11-24 kinaba: </pre> 20be503cae 2010-11-24 kinaba: <p> 20be503cae 2010-11-24 kinaba: 中身が空の関数に何を返させるかは適当です。今はとりあえず適当に文字列返してます。 20be503cae 2010-11-24 kinaba: </p> 20be503cae 2010-11-24 kinaba: )) 20be503cae 2010-11-24 kinaba: 20be503cae 2010-11-24 kinaba: $(SECTION 変数のスコープ規則, $(SECBODY 20be503cae 2010-11-24 kinaba: <p> 8caee17864 2010-11-24 kinaba: 基本的には、let によって常識的な感じに変数のスコープがネストします。 8caee17864 2010-11-24 kinaba: </p> 8caee17864 2010-11-24 kinaba: <pre> 8caee17864 2010-11-24 kinaba: let x=21 in let x=x+x in x $(D_COMMENT # 42) 8caee17864 2010-11-24 kinaba: </pre> 8caee17864 2010-11-24 kinaba: <p> 8caee17864 2010-11-24 kinaba: 一方で、"let rec" のような特別な構文はありませんが、 8caee17864 2010-11-24 kinaba: </p> 8caee17864 2010-11-24 kinaba: <pre> 3ae09b8cbf 2010-11-24 kinaba: let f = fun(x) { if x==0 then 1 else x*f(x-1) } in f(10) $(D_COMMENT # 3628800) 8caee17864 2010-11-24 kinaba: </pre> 8caee17864 2010-11-24 kinaba: <p> 8caee17864 2010-11-24 kinaba: 再帰的な関数定義なども、おそらく意図されたとおりに動きます。 8caee17864 2010-11-24 kinaba: 内部の詳細は、諸般の事情により、 8caee17864 2010-11-24 kinaba: マジカルで破壊的なスコープ規則になっているのですが、 8caee17864 2010-11-24 kinaba: 同名の変数を激しく重ねて使ったりしなければ、 8caee17864 2010-11-24 kinaba: だいたい自然な動きをすると思います、たぶん、はい。 8caee17864 2010-11-24 kinaba: </p> 8caee17864 2010-11-24 kinaba: <p> 8caee17864 2010-11-24 kinaba: ひとつだけ不可思議な動きをするのは、以下のケースです。 8caee17864 2010-11-24 kinaba: </p> 8caee17864 2010-11-24 kinaba: <pre> 8caee17864 2010-11-24 kinaba: let x = 1 in 8caee17864 2010-11-24 kinaba: let f = fun() {x} in 8caee17864 2010-11-24 kinaba: let x = 2 in 8caee17864 2010-11-24 kinaba: f() $(D_COMMENT # 2!!) 8caee17864 2010-11-24 kinaba: </pre> 8caee17864 2010-11-24 kinaba: <p> 8caee17864 2010-11-24 kinaba: let-in を縦にチェインしたときだけ、同名変数を破壊的に上書きします 8caee17864 2010-11-24 kinaba: (再帰関数の定義が"うまく"いっているのはこの上書きのためです)。 8caee17864 2010-11-24 kinaba: なんでこんなことになっているかというと、 8caee17864 2010-11-24 kinaba: 後で説明する「レイヤ」を使ったときに 8caee17864 2010-11-24 kinaba: <tt>let foo = ... in @lay foo = ... in ...</tt> 203e4cb208 2010-11-27 kinaba: で他レイヤに重ね書きするため、のつもりです。詳しくは後で。 20be503cae 2010-11-24 kinaba: </p> 20be503cae 2010-11-24 kinaba: )) 8caee17864 2010-11-24 kinaba: ) 20be503cae 2010-11-24 kinaba: )) 20be503cae 2010-11-24 kinaba: 20be503cae 2010-11-24 kinaba: 20be503cae 2010-11-24 kinaba: 20be503cae 2010-11-24 kinaba: 20be503cae 2010-11-24 kinaba: $(SECTION Basic Features, $(SECBODY 20be503cae 2010-11-24 kinaba: <p> 20be503cae 2010-11-24 kinaba: 特に特徴的でもない部分を簡単にまとめ。 20be503cae 2010-11-24 kinaba: </p> 20be503cae 2010-11-24 kinaba: <ul> 20be503cae 2010-11-24 kinaba: <li>静的型システムはありません。</li> 20be503cae 2010-11-24 kinaba: <li>"ほぼ" 純粋関数型言語です。変数やテーブルのフィールドの破壊的な書き換えはできません。<br/> 20be503cae 2010-11-24 kinaba: ただし、組み込み関数(<tt>print</tt>)と、変数のスコープ規則のマジカルな片隅に副作用があります。</li> 20be503cae 2010-11-24 kinaba: </ul> 20be503cae 2010-11-24 kinaba: <p> 20be503cae 2010-11-24 kinaba: 静的型システムがないのは意図的ですが、破壊的代入がないのは、単に実装がめんどかっただけなので、 20be503cae 2010-11-24 kinaba: 今後何か増えるかもしれません。増えないかもしれません。 20be503cae 2010-11-24 kinaba: </p> 20be503cae 2010-11-24 kinaba: $(DDOC_MEMBERS 20be503cae 2010-11-24 kinaba: $(SECTION データ型, $(SECBODY 20be503cae 2010-11-24 kinaba: <p> 20be503cae 2010-11-24 kinaba: 以下のデータ型があります。 20be503cae 2010-11-24 kinaba: </p> 20be503cae 2010-11-24 kinaba: <ul> 20be503cae 2010-11-24 kinaba: <li>整数: <tt>0</tt>, <tt>123</tt>, <tt>456666666666666666666666666666666666666789</tt>, ...</li> 20be503cae 2010-11-24 kinaba: <li>文字列: <tt>"hello, world!"</tt>, ...</li> 20be503cae 2010-11-24 kinaba: <li>関数: <tt>fun(x){x+1}</tt></li> 20be503cae 2010-11-24 kinaba: <li>テーブル: <tt>{car: 1, cdr: {car: 2, cdr: {}}}</tt></li> 203e4cb208 2010-11-27 kinaba: <li>ボトム: (特殊なケースで作られます。「レイヤ」の説明参照のこと。)</li> 20be503cae 2010-11-24 kinaba: </ul> 20be503cae 2010-11-24 kinaba: <p> 20be503cae 2010-11-24 kinaba: 関数はいわゆる「クロージャ」です。静的スコープで外側の環境にアクセスできます。 20be503cae 2010-11-24 kinaba: テーブルはいわゆるプロトタイプチェーンを持っていて、 20be503cae 2010-11-24 kinaba: 自分にないフィールドの場合は親に問い合わせが行く感じになっていますが、 20be503cae 2010-11-24 kinaba: フィールドの書き換えがないので、これは特に意味ないかもしれない…。 c0158c9281 2010-11-24 kinaba: </p> c0158c9281 2010-11-24 kinaba: <p> c0158c9281 2010-11-24 kinaba: また、リストを扱うために、いわゆる「cons リスト」を使います。 c0158c9281 2010-11-24 kinaba: 空リストを <tt>{}</tt>、1個以上要素があるものを <tt>{car: 先頭要素, cdr: 二番目以降のリスト}</tt> c0158c9281 2010-11-24 kinaba: という形で。この形でリストを扱わなければならないという決まりはありませんが、 c0158c9281 2010-11-24 kinaba: この形は特別扱いされて <tt>print</tt> で綺麗に出力されたりします。 8caee17864 2010-11-24 kinaba: </p> 20be503cae 2010-11-24 kinaba: )) 20be503cae 2010-11-24 kinaba: $(SECTION パターンマッチ, $(SECBODY 8caee17864 2010-11-24 kinaba: <p> 8caee17864 2010-11-24 kinaba: 適当に実装されたパターンマッチがあります。 8caee17864 2010-11-24 kinaba: リストの 2n 番目と 2n+1 番目を足して長さを半分にする関数: 8caee17864 2010-11-24 kinaba: </p> 8caee17864 2010-11-24 kinaba: <pre> 8caee17864 2010-11-24 kinaba: def adjSum(lst) 8caee17864 2010-11-24 kinaba: { 3ae09b8cbf 2010-11-24 kinaba: case lst 3ae09b8cbf 2010-11-24 kinaba: when {car:x, cdr:{car: y, cdr:z}}: {car: x+y, cdr: adjSum(z)} 3ae09b8cbf 2010-11-24 kinaba: when {car:x, cdr:{}}: lst 3ae09b8cbf 2010-11-24 kinaba: when {}: {} 8caee17864 2010-11-24 kinaba: } 8caee17864 2010-11-24 kinaba: </pre> 8caee17864 2010-11-24 kinaba: <p> 8caee17864 2010-11-24 kinaba: 動かすときには、処理系がそれっぽい if-then-else に展開しています。 8caee17864 2010-11-24 kinaba: <tt>when</tt> を上から試していって、最初にマッチしたところを実行します。 f7e9e77316 2010-11-26 kinaba: どれにもマッチしないとエラーでプログラム終了します。 8caee17864 2010-11-24 kinaba: </p> 8caee17864 2010-11-24 kinaba: <pre> 8caee17864 2010-11-24 kinaba: PAT ::= "_" $(D_COMMENT # ワイルドカード) 8caee17864 2010-11-24 kinaba: | ID $(D_COMMENT # 変数パターン) 8caee17864 2010-11-24 kinaba: | "{" ID ":" PAT "," ... "," ID : PAT "}" $(D_COMMENT # テーブルパターン) 8caee17864 2010-11-24 kinaba: | E $(D_COMMENT # 値パターン) 8caee17864 2010-11-24 kinaba: </pre> 8caee17864 2010-11-24 kinaba: <p> 8caee17864 2010-11-24 kinaba: 変数パターンは常にマッチして、値をその変数に束縛します。 8caee17864 2010-11-24 kinaba: ワイルドカードも常にマッチしますが、変数束縛しません。 8caee17864 2010-11-24 kinaba: 値パターンは、任意の式が書けます。その式を評価した結果と <tt>==</tt> ならマッチします。 8caee17864 2010-11-24 kinaba: 外で束縛された変数を値パターンとして配置、は直接はできないので 8caee17864 2010-11-24 kinaba: </p> 8caee17864 2010-11-24 kinaba: <pre> 8caee17864 2010-11-24 kinaba: var x = 123; 3ae09b8cbf 2010-11-24 kinaba: case foo 3ae09b8cbf 2010-11-24 kinaba: when {val: x+0}: ... $(D_COMMENT # これは {val:123} と同じ) 3ae09b8cbf 2010-11-24 kinaba: when {val: x}: ... $(D_COMMENT # これは任意の foo.?val なら常にマッチ) 8caee17864 2010-11-24 kinaba: </pre> 8caee17864 2010-11-24 kinaba: <p> 8caee17864 2010-11-24 kinaba: 適当にちょっと複雑な式にしてやるとよいかも(裏技)。 8caee17864 2010-11-24 kinaba: </p> 8caee17864 2010-11-24 kinaba: <p> 8caee17864 2010-11-24 kinaba: テーブルパターンは、書かれたキーが全てあればマッチします。 8caee17864 2010-11-24 kinaba: <tt>{a: _}</tt> は、<tt>.a</tt> を持ってさえいればマッチするので、 8caee17864 2010-11-24 kinaba: <tt>{a: 123, b: 456}</tt> なんかにもマッチします。 8caee17864 2010-11-24 kinaba: なので、リストに対するパターンを書くときには、car/cdr の場合を先に書かないと 3ae09b8cbf 2010-11-24 kinaba: <tt>when {}</tt> を上に書くと全部マッチしちゃいます。注意。 8caee17864 2010-11-24 kinaba: </p> 20be503cae 2010-11-24 kinaba: )) 20be503cae 2010-11-24 kinaba: ) 20be503cae 2010-11-24 kinaba: )) 20be503cae 2010-11-24 kinaba: 20be503cae 2010-11-24 kinaba: 20be503cae 2010-11-24 kinaba: 20be503cae 2010-11-24 kinaba: 20be503cae 2010-11-24 kinaba: 20be503cae 2010-11-24 kinaba: $(SECTION Layers, $(SECBODY a795c97dc3 2010-11-27 kinaba: <p> a795c97dc3 2010-11-27 kinaba: この言語の唯一の特徴的な部分は、「レイヤ」機能です。 a795c97dc3 2010-11-27 kinaba: </p> 005474ba5b 2010-11-27 kinaba: <p> 005474ba5b 2010-11-27 kinaba: ひとつのコードに複数の「意味」を持たせるのが、レイヤ機能の目的です。 005474ba5b 2010-11-27 kinaba: </p> a795c97dc3 2010-11-27 kinaba: $(DDOC_MEMBERS 005474ba5b 2010-11-27 kinaba: $(SECTION 概要, $(SECBODY 005474ba5b 2010-11-27 kinaba: <p> 005474ba5b 2010-11-27 kinaba: 普通に Polemy のコードを動かすと、そのコードは「<tt>@value</tt> レイヤ」で動作します。 005474ba5b 2010-11-27 kinaba: インタプリタで実験。 005474ba5b 2010-11-27 kinaba: </p> 20be503cae 2010-11-24 kinaba: <pre> 005474ba5b 2010-11-27 kinaba: $ bin/polemy 005474ba5b 2010-11-27 kinaba: Welcome to Polemy 0.1.0 005474ba5b 2010-11-27 kinaba: >> 1 + 2 20be503cae 2010-11-24 kinaba: 3 005474ba5b 2010-11-27 kinaba: </pre> 005474ba5b 2010-11-27 kinaba: この、普通に、数字の 1 は数字の 1 として、2 は 2 として、足し算は足し算として実行するのが、 005474ba5b 2010-11-27 kinaba: 「<tt>@value</tt> レイヤ」です。 005474ba5b 2010-11-27 kinaba: レイヤを明示的に指定するには、<tt>レイヤ名( ... )</tt> という構文を使います。 005474ba5b 2010-11-27 kinaba: $(RED $(B レイヤ指定式)) と読んでいます。 005474ba5b 2010-11-27 kinaba: つまり、さっきのコードは以下のようにも書けます。 005474ba5b 2010-11-27 kinaba: <pre> 005474ba5b 2010-11-27 kinaba: >> @value( 1 + 2 ) 20be503cae 2010-11-24 kinaba: 3 005474ba5b 2010-11-27 kinaba: </pre> 005474ba5b 2010-11-27 kinaba: 他のレイヤで動かしてみましょう。適当に。「<tt>@hoge</tt> レイヤ」で。 005474ba5b 2010-11-27 kinaba: <pre> 005474ba5b 2010-11-27 kinaba: >> @hoge( 3 ) 005474ba5b 2010-11-27 kinaba: polemy.failure.RuntimeException@C:\Develop\Projects\Polemy\polemy\eval.d(138): 005474ba5b 2010-11-27 kinaba: [<REPL>:4:8] lift function for @hoge is not registered 005474ba5b 2010-11-27 kinaba: </pre> 005474ba5b 2010-11-27 kinaba: <p> 005474ba5b 2010-11-27 kinaba: エラーになりました。Polemy のインタプリタは、起動時には、<tt>@value</tt> 005474ba5b 2010-11-27 kinaba: レイヤでのコードの意味しか知りません。<tt>@hoge</tt> レイヤでは <tt>3</tt> 005474ba5b 2010-11-27 kinaba: というのがどんな意味なのか、わかりません!というエラーが出ています。 005474ba5b 2010-11-27 kinaba: </p> 005474ba5b 2010-11-27 kinaba: <p> 005474ba5b 2010-11-27 kinaba: これを教えてあげるためには、<tt>@hoge</tt> レイヤの $(RED $(B リフト関数)) というものを定義します。 005474ba5b 2010-11-27 kinaba: </p> 005474ba5b 2010-11-27 kinaba: <pre> 005474ba5b 2010-11-27 kinaba: >> @@hoge = fun(x){ x*2 } 005474ba5b 2010-11-27 kinaba: (function:1bdc5c0:1ba8580) 005474ba5b 2010-11-27 kinaba: </pre> 005474ba5b 2010-11-27 kinaba: <p> 005474ba5b 2010-11-27 kinaba: <tt>@hoge</tt> レイヤでは、<tt>1</tt> というコードの意味は <tt>2</tt>、 005474ba5b 2010-11-27 kinaba: <tt>2</tt> というコードの意味は <tt>4</tt>、…、という、全部「2倍した意味」を持っていることにします。 005474ba5b 2010-11-27 kinaba: 「<tt>@ レイヤ名 = ...</tt>」 という構文を使います。 005474ba5b 2010-11-27 kinaba: ここには、「<tt>@value</tt> レイヤでの値 <tt>x</tt> は <tt>@hoge</tt> レイヤではどういう意味になるか?」 005474ba5b 2010-11-27 kinaba: を計算して返す関数を登録します。 005474ba5b 2010-11-27 kinaba: これで、Polemy にも、<tt>@hoge</tt> レイヤの意味がわかるようになりました。 005474ba5b 2010-11-27 kinaba: </p> 005474ba5b 2010-11-27 kinaba: <pre> 005474ba5b 2010-11-27 kinaba: >> @hoge( 3 ) 005474ba5b 2010-11-27 kinaba: 6 005474ba5b 2010-11-27 kinaba: </pre> 005474ba5b 2010-11-27 kinaba: <p> 005474ba5b 2010-11-27 kinaba: では、1+2 を <tt>@hoge</tt> レイヤで動かしてみましょう。 005474ba5b 2010-11-27 kinaba: </p> 005474ba5b 2010-11-27 kinaba: <pre> 005474ba5b 2010-11-27 kinaba: >> @hoge( 1 + 2 ) 005474ba5b 2010-11-27 kinaba: polemy.failure.RuntimeException@C:\Develop\Projects\Polemy\polemy\eval.d(466): 005474ba5b 2010-11-27 kinaba: [<REPL>:3:7] only @value layer can call native function: + 005474ba5b 2010-11-27 kinaba: [<REPL>:3:7] + 005474ba5b 2010-11-27 kinaba: </pre> 005474ba5b 2010-11-27 kinaba: <p> 6de3d8df3a 2010-11-27 kinaba: まだエラーですね。これは要するに "+" の意味がわからない、と言っています。 6de3d8df3a 2010-11-27 kinaba: $(RED $(B レイヤ指定変数定義式)) で、"+" の意味を教えてあげます。 005474ba5b 2010-11-27 kinaba: </p> 005474ba5b 2010-11-27 kinaba: <pre> 005474ba5b 2010-11-27 kinaba: >> @hoge "+" = fun(x, y) {x} 6de3d8df3a 2010-11-27 kinaba: (function:182eca0:18435e0) 6de3d8df3a 2010-11-27 kinaba: >> @hoge( 3 + 4 ) 6de3d8df3a 2010-11-27 kinaba: 6 6de3d8df3a 2010-11-27 kinaba: </pre> 6de3d8df3a 2010-11-27 kinaba: <p> 6de3d8df3a 2010-11-27 kinaba: できました。 6de3d8df3a 2010-11-27 kinaba: </p> 6de3d8df3a 2010-11-27 kinaba: <p> 6de3d8df3a 2010-11-27 kinaba: 他の組み込み関数の意味も決めてみましょう。この <tt>@hoge</tt> レイヤでは、 6de3d8df3a 2010-11-27 kinaba: 引き算のつもりで書いたコードが、掛け算になってしまうのだ! 6de3d8df3a 2010-11-27 kinaba: </p> 6de3d8df3a 2010-11-27 kinaba: <pre> 6de3d8df3a 2010-11-27 kinaba: >> @hoge "-" = fun(x, y) {x * y} 6de3d8df3a 2010-11-27 kinaba: (function:1b4c6a0:1b4fbe0) 6de3d8df3a 2010-11-27 kinaba: >> @hoge( 5 - 6 ) 6de3d8df3a 2010-11-27 kinaba: polemy.failure.RuntimeException@C:\Develop\Projects\Polemy\polemy\eval.d(469): 6de3d8df3a 2010-11-27 kinaba: [<REPL>:3:24] only @value layer can call native function: * 6de3d8df3a 2010-11-27 kinaba: [<REPL>:3:24] * 6de3d8df3a 2010-11-27 kinaba: [<REPL>:4:8] - 6de3d8df3a 2010-11-27 kinaba: </pre> 6de3d8df3a 2010-11-27 kinaba: <p> 6de3d8df3a 2010-11-27 kinaba: 5、の意味は 10 で 6 の意味は 12 なので、10 - 12 と見せかけて掛け算して 120 が返るのだ! 6de3d8df3a 2010-11-27 kinaba: と思いきや、エラーになってしまいました。なぜでしょう。それは、この "-" の定義、 6de3d8df3a 2010-11-27 kinaba: <code>fun(x, y) {x * y}</code> 自体が、<tt>@hoge</tt> レイヤで実行されるからです。 6de3d8df3a 2010-11-27 kinaba: 掛け算はまだ定義していません。 6de3d8df3a 2010-11-27 kinaba: </p> 6de3d8df3a 2010-11-27 kinaba: <p> 6de3d8df3a 2010-11-27 kinaba: ここは、「普通の」意味の掛け算を使いたいのです。 6de3d8df3a 2010-11-27 kinaba: この部分については、<tt>@value</tt> レイヤで計算して欲しい。 6de3d8df3a 2010-11-27 kinaba: そんなときは、レイヤ指定式を使います。 6de3d8df3a 2010-11-27 kinaba: </p> 6de3d8df3a 2010-11-27 kinaba: <pre> 6de3d8df3a 2010-11-27 kinaba: >> @hoge "-" = fun(x, y) {$(B @value(@hoge(x) * @hoge(y)))} 6de3d8df3a 2010-11-27 kinaba: (function:1b086c0:1b4fbe0) 6de3d8df3a 2010-11-27 kinaba: >> @hoge( 5 - 6 ) 6de3d8df3a 2010-11-27 kinaba: 120 6de3d8df3a 2010-11-27 kinaba: </pre> 6de3d8df3a 2010-11-27 kinaba: <p> 6de3d8df3a 2010-11-27 kinaba: できました。掛け算は、<tt>@value</tt> レイヤの意味で実行します。 6de3d8df3a 2010-11-27 kinaba: 各変数は、<tt>@hoge</tt> レイヤで計算された意味を使います、という意味になります。 6de3d8df3a 2010-11-27 kinaba: </p> 6de3d8df3a 2010-11-27 kinaba: )) 6de3d8df3a 2010-11-27 kinaba: $(SECTION 関数の自動リフト, $(SECBODY 6de3d8df3a 2010-11-27 kinaba: <p> 6de3d8df3a 2010-11-27 kinaba: 続きです。ちょっと関数を定義してみました。 6de3d8df3a 2010-11-27 kinaba: </p> 6de3d8df3a 2010-11-27 kinaba: <pre> 6de3d8df3a 2010-11-27 kinaba: >> def twoMinus(x,y,z) { x - y - z } 6de3d8df3a 2010-11-27 kinaba: (function:1b26420:1b4fbe0) 6de3d8df3a 2010-11-27 kinaba: >> twoMinus(1,2,3) 6de3d8df3a 2010-11-27 kinaba: -4 6de3d8df3a 2010-11-27 kinaba: </pre> 6de3d8df3a 2010-11-27 kinaba: <p> 6de3d8df3a 2010-11-27 kinaba: <tt>@value</tt> レイヤで実行すると、当然、1 から 2 と 3 を引いて、-4 です。 6de3d8df3a 2010-11-27 kinaba: </p> 6de3d8df3a 2010-11-27 kinaba: <pre> 6de3d8df3a 2010-11-27 kinaba: >> @hoge( twoMinus(1,2,3) ) 6de3d8df3a 2010-11-27 kinaba: 48 6de3d8df3a 2010-11-27 kinaba: </pre> 6de3d8df3a 2010-11-27 kinaba: <p> 6de3d8df3a 2010-11-27 kinaba: <tt>@hoge</tt> レイヤだと、2 と 4 と 6 を掛け算するので、結果は 48 です。 6de3d8df3a 2010-11-27 kinaba: </p> 6de3d8df3a 2010-11-27 kinaba: <p> 6de3d8df3a 2010-11-27 kinaba: 1, 2, 3 のような値と、+ や - のような組み込み関数については、 6de3d8df3a 2010-11-27 kinaba: 「<tt>@hoge</tt> レイヤでの意味」をレイヤを定義する人が決めてやる必要があります。 6de3d8df3a 2010-11-27 kinaba: でも、それさえ決めれば、あとはプログラム中で自分で定義した関数はすべて、 6de3d8df3a 2010-11-27 kinaba: Polemy 側で自動的にそのレイヤでの意味で実行できるようになります。 6de3d8df3a 2010-11-27 kinaba: </p> 6de3d8df3a 2010-11-27 kinaba: <p> 6de3d8df3a 2010-11-27 kinaba: レイヤ指定変数定義を使って、変数の意味をそのレイヤでだけ上書きして、 6de3d8df3a 2010-11-27 kinaba: 違う意味を与えてやっても構いません。 6de3d8df3a 2010-11-27 kinaba: </p> 6de3d8df3a 2010-11-27 kinaba: <pre> 6de3d8df3a 2010-11-27 kinaba: >> def twoMinus(x,y,z) { x - y - z } $(D_COMMENT # @value レイヤでの定義) 6de3d8df3a 2010-11-27 kinaba: >> @hoge twoMinus(x,y,z) { 21 } $(D_COMMENT # @hoge レイヤでの定義) 6de3d8df3a 2010-11-27 kinaba: >> twoMinus(1,2,3) 6de3d8df3a 2010-11-27 kinaba: -4 6de3d8df3a 2010-11-27 kinaba: >> @hoge( twoMinus(1,2,3) ) 6de3d8df3a 2010-11-27 kinaba: 42 6de3d8df3a 2010-11-27 kinaba: </pre> 6de3d8df3a 2010-11-27 kinaba: <p> 6de3d8df3a 2010-11-27 kinaba: こんな感じで。 6de3d8df3a 2010-11-27 kinaba: </p> 6de3d8df3a 2010-11-27 kinaba: )) 6de3d8df3a 2010-11-27 kinaba: $(SECTION レイヤ指定引数, $(SECBODY 6de3d8df3a 2010-11-27 kinaba: <p> 6de3d8df3a 2010-11-27 kinaba: ここまでのサンプルでは、コードを書いた人が、レイヤ指定式で明示的にレイヤを切り替えていました。 6de3d8df3a 2010-11-27 kinaba: $(RED $(B レイヤ指定引数)) を使うと、ライブラリ関数などを書くときに、 6de3d8df3a 2010-11-27 kinaba: 「この関数の第2引数は <tt>@hoge</tt> レイヤで計算して欲しい」 6de3d8df3a 2010-11-27 kinaba: といった指定ができます。 6de3d8df3a 2010-11-27 kinaba: </p> 6de3d8df3a 2010-11-27 kinaba: <pre> 6de3d8df3a 2010-11-27 kinaba: >> def f(x, y $(B @hoge)) { x + @hoge(y) } 6de3d8df3a 2010-11-27 kinaba: >> f(1, 2) 6de3d8df3a 2010-11-27 kinaba: 5 6de3d8df3a 2010-11-27 kinaba: </pre> 6de3d8df3a 2010-11-27 kinaba: <p> 6de3d8df3a 2010-11-27 kinaba: f の第2引数は、必ず <tt>@hoge</tt> レイヤで解釈されます。 6de3d8df3a 2010-11-27 kinaba: </p> 6de3d8df3a 2010-11-27 kinaba: <pre> 6de3d8df3a 2010-11-27 kinaba: >> def ff(x, y $(B @hoge @value)) { x + @hoge(y) + @value(y) } 6de3d8df3a 2010-11-27 kinaba: >> ff(1, 2) 6de3d8df3a 2010-11-27 kinaba: 7 6de3d8df3a 2010-11-27 kinaba: </pre> 6de3d8df3a 2010-11-27 kinaba: <p> 6de3d8df3a 2010-11-27 kinaba: <tt>@hoge</tt> と <tt>@value</tt> の両方のレイヤで解釈して欲しい、という欲張りな人は、 6de3d8df3a 2010-11-27 kinaba: レイヤ指定を複数並べて下さい。 6de3d8df3a 2010-11-27 kinaba: </p> 6de3d8df3a 2010-11-27 kinaba: <p> 6de3d8df3a 2010-11-27 kinaba: なにもレイヤ指定がないと、$(RED $(B ニュートラルレイヤ指定)) と呼ばれ、 6de3d8df3a 2010-11-27 kinaba: その関数の呼び出し側が解釈されていたレイヤと同じところにセットされます。 6de3d8df3a 2010-11-27 kinaba: <tt>let</tt>, <tt>var</tt>, <tt>def</tt> による変数定義も同じで、 6de3d8df3a 2010-11-27 kinaba: <tt>@hoge x = ...</tt> とレイヤを明示するとそのレイヤでの変数の意味が定義されますが、 6de3d8df3a 2010-11-27 kinaba: <tt>let x = ...</tt> とレイヤ指定しないで書くと、現在解釈中のレイヤに定義、という動作をします。 6de3d8df3a 2010-11-27 kinaba: </p> 6de3d8df3a 2010-11-27 kinaba: )) 6de3d8df3a 2010-11-27 kinaba: $(SECTION ボトムと自動メモ化, $(SECBODY 6de3d8df3a 2010-11-27 kinaba: <p> 6de3d8df3a 2010-11-27 kinaba: パターンマッチ失敗時と、"..." という式を実行したときと、再帰が無限に止まらなくなったとき、 6de3d8df3a 2010-11-27 kinaba: には、Polemy のコードは実行時エラーで終了します……<tt>@value</tt> レイヤならば。 6de3d8df3a 2010-11-27 kinaba: </p> 6de3d8df3a 2010-11-27 kinaba: <p> 6de3d8df3a 2010-11-27 kinaba: ユーザー定義レイヤでは、このような時にも実行時エラーにならず、 6de3d8df3a 2010-11-27 kinaba: 「$(RED $(B ボトム))」という特別な値がリフト関数に渡されます。 6de3d8df3a 2010-11-27 kinaba: 組み込みの <tt>_isbot</tt> 関数で、ボトムかどうか判定できます。 6de3d8df3a 2010-11-27 kinaba: </p> 6de3d8df3a 2010-11-27 kinaba: <p> 6de3d8df3a 2010-11-27 kinaba: 「再帰が無限に止まらなくなったとき」は、 6de3d8df3a 2010-11-27 kinaba: ある引数で呼び出された関数が、return するよりも前にまた同じ引数で呼び出されたら、 6de3d8df3a 2010-11-27 kinaba: ループしていると見なすことで判定しています。 6de3d8df3a 2010-11-27 kinaba: これを判定する実装の副作用として、ユーザー定義のレイヤでは、関数は全てメモ化されています。 6de3d8df3a 2010-11-27 kinaba: つまり、ある関数が2回同じ引数同じ環境で呼び出されたら、1回目の答えをキャッシュしておいて、 6de3d8df3a 2010-11-27 kinaba: 2回目は計算をせずに即座にキャッシュをひいて答えを返します。 6de3d8df3a 2010-11-27 kinaba: </p> 6de3d8df3a 2010-11-27 kinaba: )) 6de3d8df3a 2010-11-27 kinaba: $(SECTION まとめ, $(SECBODY 6de3d8df3a 2010-11-27 kinaba: <p> 6de3d8df3a 2010-11-27 kinaba: まとめると、以下の機能があります。 6de3d8df3a 2010-11-27 kinaba: </p> 6de3d8df3a 2010-11-27 kinaba: <ul> 6de3d8df3a 2010-11-27 kinaba: <li><tt>@@layer = fun(x) { ... } in ...</tt> で、 6de3d8df3a 2010-11-27 kinaba: <tt>@value</tt> レイヤの値に別のレイヤでの意味を与えるリフト関数を定義</li> 6de3d8df3a 2010-11-27 kinaba: <li><tt>@layer x = ... in ...</tt> で、そのレイヤでのその変数の意味を定義</li> 6de3d8df3a 2010-11-27 kinaba: <li>どちらも let/var/def 式の特殊形なので、<tt>@@layer(x) { ... } in ...</tt> などの略記も可。</li> 6de3d8df3a 2010-11-27 kinaba: <li>式の途中で @layer( ... ) と書くと、レイヤを明示的に切り替えられる</li> 6de3d8df3a 2010-11-27 kinaba: <li>関数の仮引数に fun(x @layer){ ... } とレイヤを指定すると、 6de3d8df3a 2010-11-27 kinaba: 対応する実引数はそのレイヤで解釈される。</li> 6de3d8df3a 2010-11-27 kinaba: </ul> 6de3d8df3a 2010-11-27 kinaba: <p> 6de3d8df3a 2010-11-27 kinaba: </p> 6de3d8df3a 2010-11-27 kinaba: )) 6de3d8df3a 2010-11-27 kinaba: $(SECTION 例, $(SECBODY 6de3d8df3a 2010-11-27 kinaba: <p> 6de3d8df3a 2010-11-27 kinaba: 具体的な「値」のかわりに、その「メタ情報」を取り出して、それが処理によってどう変化するか、 6de3d8df3a 2010-11-27 kinaba: といった情報を解析するのを主な用途として、この機能を作ってみました。 6de3d8df3a 2010-11-27 kinaba: プログラムでよく使われる代表的なメタ情報は、「型」です。 6de3d8df3a 2010-11-27 kinaba: サンプルとしては、sample/type.pmy をご覧下さい。以下、簡単な概略。 6de3d8df3a 2010-11-27 kinaba: </p> 6de3d8df3a 2010-11-27 kinaba: <pre> 6de3d8df3a 2010-11-27 kinaba: @@type = fun(x) { 6de3d8df3a 2010-11-27 kinaba: if( _isint(x) ) then "int" 6de3d8df3a 2010-11-27 kinaba: else if( _isstr(x) ) then "str" 6de3d8df3a 2010-11-27 kinaba: else if( _isbot(x) ) then "runtime error" 6de3d8df3a 2010-11-27 kinaba: else "type error" 6de3d8df3a 2010-11-27 kinaba: } 6de3d8df3a 2010-11-27 kinaba: </pre> 6de3d8df3a 2010-11-27 kinaba: <pre> 6de3d8df3a 2010-11-27 kinaba: >> @type( 1 ) 20be503cae 2010-11-24 kinaba: int 6de3d8df3a 2010-11-27 kinaba: >> @type( 2 ) 20be503cae 2010-11-24 kinaba: int 6de3d8df3a 2010-11-27 kinaba: >> @type( "foo" ) 6de3d8df3a 2010-11-27 kinaba: str 6de3d8df3a 2010-11-27 kinaba: </pre> 6de3d8df3a 2010-11-27 kinaba: <p> 6de3d8df3a 2010-11-27 kinaba: こんな風に、値をメタ情報へ抽象化するのが、リフト関数です。 6de3d8df3a 2010-11-27 kinaba: </p> 6de3d8df3a 2010-11-27 kinaba: <p> 6de3d8df3a 2010-11-27 kinaba: 型に抽象化したレイヤでの、組み込み関数の意味を考えましょう。 6de3d8df3a 2010-11-27 kinaba: "+" は、"int" と "int" を足したら "int" を返す関数です。 6de3d8df3a 2010-11-27 kinaba: それ以外なら"型エラー"を返します。そういう関数です。 6de3d8df3a 2010-11-27 kinaba: </p> 6de3d8df3a 2010-11-27 kinaba: <pre> 6de3d8df3a 2010-11-27 kinaba: var int_int_int = fun (x, y) {@value( 6de3d8df3a 2010-11-27 kinaba: var tx = @type(x); 6de3d8df3a 2010-11-27 kinaba: var ty = @type(y); 6de3d8df3a 2010-11-27 kinaba: if tx=="runtime error" then ty 6de3d8df3a 2010-11-27 kinaba: else if ty=="runtime error" then tx 6de3d8df3a 2010-11-27 kinaba: else if tx=="int" && ty=="int" then "int" 6de3d8df3a 2010-11-27 kinaba: else "type error" 6de3d8df3a 2010-11-27 kinaba: )}; 20be503cae 2010-11-24 kinaba: 6de3d8df3a 2010-11-27 kinaba: @type "+" = int_int_int; 6de3d8df3a 2010-11-27 kinaba: @type "-" = int_int_int; 6de3d8df3a 2010-11-27 kinaba: @type "<" = int_int_int; 6de3d8df3a 2010-11-27 kinaba: </pre> 6de3d8df3a 2010-11-27 kinaba: <pre> 6de3d8df3a 2010-11-27 kinaba: >> @type( 1 + 2 ) 20be503cae 2010-11-24 kinaba: int 6de3d8df3a 2010-11-27 kinaba: >> @type( 1 + "foo" ) 6de3d8df3a 2010-11-27 kinaba: type error 6de3d8df3a 2010-11-27 kinaba: </pre> 6de3d8df3a 2010-11-27 kinaba: <p> 6de3d8df3a 2010-11-27 kinaba: 「実行時エラーについては、それが起きなければ返すはずの型」を計算するという定義に、 6de3d8df3a 2010-11-27 kinaba: ここではしています。さらに(ちょっと手抜きで int 以外を考えていない)if の型定義を考えると、 6de3d8df3a 2010-11-27 kinaba: こんな雰囲気。 6de3d8df3a 2010-11-27 kinaba: </p> 6de3d8df3a 2010-11-27 kinaba: <pre> 6de3d8df3a 2010-11-27 kinaba: @type "if" (c, t, e) {@value( 6de3d8df3a 2010-11-27 kinaba: if( @type(c)=="int" || @type(c)=="runtime error" ) then 6de3d8df3a 2010-11-27 kinaba: @type( int_int_int(t(), e()) ) 6de3d8df3a 2010-11-27 kinaba: else 6de3d8df3a 2010-11-27 kinaba: "type error" 6de3d8df3a 2010-11-27 kinaba: )} 6de3d8df3a 2010-11-27 kinaba: </pre> 6de3d8df3a 2010-11-27 kinaba: <p> 6de3d8df3a 2010-11-27 kinaba: 関数が自動リフトされるので、フィボナッチ関数の型を調べることができます。 6de3d8df3a 2010-11-27 kinaba: </p> 6de3d8df3a 2010-11-27 kinaba: <pre> 6de3d8df3a 2010-11-27 kinaba: >> def fib(x) { if x<2 then 1 else fib(x-1)+fib(x-2) }; 6de3d8df3a 2010-11-27 kinaba: >> @type( fib(100000000000000) ) 6de3d8df3a 2010-11-27 kinaba: int 6de3d8df3a 2010-11-27 kinaba: >> def gib(x) { if x<2 then 1 else gib(x-1)+gib(x-"str") }; 6de3d8df3a 2010-11-27 kinaba: >> @type( gib(100000000000000) ) 6de3d8df3a 2010-11-27 kinaba: type error 6de3d8df3a 2010-11-27 kinaba: </pre> 6de3d8df3a 2010-11-27 kinaba: <p> 6de3d8df3a 2010-11-27 kinaba: この定義で <tt>fib(100000000000000)</tt> を <tt>@value</tt> レイヤで普通に計算して、 6de3d8df3a 2010-11-27 kinaba: 結果の型を見る、というのでは時間がいくらあっても足りません。 6de3d8df3a 2010-11-27 kinaba: いったん <tt>@type</tt> のメタ情報の世界に移ってから計算できるのが、レイヤ機能の肝です。 6de3d8df3a 2010-11-27 kinaba: </p> 6de3d8df3a 2010-11-27 kinaba: <p> 6de3d8df3a 2010-11-27 kinaba: 正確には、この定義で <tt>@type</tt> レイヤに移ると fib("int") を無限に呼び出し続けて止まらなくなるのですが、 6de3d8df3a 2010-11-27 kinaba: そこは、自動メモ化による再帰検出でボトム値を返す機能によって、うまく止まっています。 6de3d8df3a 2010-11-27 kinaba: </p> 6de3d8df3a 2010-11-27 kinaba: <p> 6de3d8df3a 2010-11-27 kinaba: それでも上手く型計算ができない(あるいはすごく遅くなる)ような複雑な関数があるかもしれません。 6de3d8df3a 2010-11-27 kinaba: 仕方がないので、型情報をアノテーションとしてつけてあげることも可能です。 6de3d8df3a 2010-11-27 kinaba: </p> 6de3d8df3a 2010-11-27 kinaba: <pre> 6de3d8df3a 2010-11-27 kinaba: @type f = int_int_int; 6de3d8df3a 2010-11-27 kinaba: def f(x,y) { ...とても型を計算できないくらい複雑な定義... }; 8caee17864 2010-11-24 kinaba: </pre> 6de3d8df3a 2010-11-27 kinaba: <p> 6de3d8df3a 2010-11-27 kinaba: これが、レイヤ指定変数定義の典型的な使い道です。 6de3d8df3a 2010-11-27 kinaba: </p> a795c97dc3 2010-11-27 kinaba: )) a795c97dc3 2010-11-27 kinaba: ) 8caee17864 2010-11-24 kinaba: )) 20be503cae 2010-11-24 kinaba: 20be503cae 2010-11-24 kinaba: 8caee17864 2010-11-24 kinaba: $(SECTION Macro Layers, $(SECBODY 8caee17864 2010-11-24 kinaba: <p> 8caee17864 2010-11-24 kinaba: Polemy 言語組み込みのレイヤは <code>@value</code> と <code>@macro</code> の二つです。 8caee17864 2010-11-24 kinaba: (内部的にはもういくつかありますが、ユーザから直接は使えません。) 8caee17864 2010-11-24 kinaba: <code>@value</code> は、「普通に」普通のセマンティクスでプログラムを実行するレイヤでした。 8caee17864 2010-11-24 kinaba: <code>@macro</code> は、実は、<code>@value</code> よりも前に実行されるレイヤで、 8caee17864 2010-11-24 kinaba: 「プログラムを実行するとその構文木を返す」というセマンティクスで動きます。 8caee17864 2010-11-24 kinaba: </p> 8caee17864 2010-11-24 kinaba: <p> 8caee17864 2010-11-24 kinaba: 動きとしてはこうです。 8caee17864 2010-11-24 kinaba: </p> 8caee17864 2010-11-24 kinaba: <ol> 8caee17864 2010-11-24 kinaba: <li>関数呼び出し時(とトップレベル環境の実行開始時)に、 8caee17864 2010-11-24 kinaba: まず、<code>@macro</code> レイヤでコードを実行。</li> 203e4cb208 2010-11-27 kinaba: <li>返ってきた構文木を、その関数を呼び出したときのレイヤで実行。</li> 8caee17864 2010-11-24 kinaba: </ol> 8caee17864 2010-11-24 kinaba: <p> 8caee17864 2010-11-24 kinaba: <code>@macro</code> レイヤも所詮ただのレイヤですので、 8caee17864 2010-11-24 kinaba: 上で説明した方法で <code>@macro</code> レイヤに関数などを登録しておくことで、 8caee17864 2010-11-24 kinaba: 構文木の生成をいじることが可能です。まさにマクロ。 8caee17864 2010-11-24 kinaba: </p> 20be503cae 2010-11-24 kinaba: 8caee17864 2010-11-24 kinaba: $(DDOC_MEMBERS 207cea338a 2010-11-26 kinaba: $(SECTION 概要, $(SECBODY 207cea338a 2010-11-26 kinaba: <p> 207cea338a 2010-11-26 kinaba: samples/macro.pmy にいくつか使い方サンプルが置いてありますので、詳しくはそちらをどうぞ。 207cea338a 2010-11-26 kinaba: </p> 207cea338a 2010-11-26 kinaba: <pre> 207cea338a 2010-11-26 kinaba: >> @macro( twice(print("Hello")) ) 207cea338a 2010-11-26 kinaba: { 207cea338a 2010-11-26 kinaba: pos: {lineno:1, column:9, filename:<REPL>}, 207cea338a 2010-11-26 kinaba: args: [ { pos: {lineno:1, column:15, filename:<REPL>}, 207cea338a 2010-11-26 kinaba: args: [{pos:{lineno:1, column:21, filename:<REPL>}, 207cea338a 2010-11-26 kinaba: is:Str, 207cea338a 2010-11-26 kinaba: data:Hello}], 207cea338a 2010-11-26 kinaba: is: App, 207cea338a 2010-11-26 kinaba: fun: {pos:{lineno:1, column:15, filename:<REPL>}, is:Var, name:print}} 207cea338a 2010-11-26 kinaba: ], 207cea338a 2010-11-26 kinaba: is: App, 207cea338a 2010-11-26 kinaba: fun: {pos:{lineno:1, column:9, filename:<REPL>}, is:Var, name:twice} 207cea338a 2010-11-26 kinaba: } 207cea338a 2010-11-26 kinaba: </pre> 207cea338a 2010-11-26 kinaba: <p> 207cea338a 2010-11-26 kinaba: 詳細は気にしなくて構いませんが、とにかく、<tt>@macro</tt> レイヤでは、 207cea338a 2010-11-26 kinaba: 基本的には、コードを実行するとそのコードの構文木がでてきます。 207cea338a 2010-11-26 kinaba: この挙動は <tt>@macro</tt> レイヤの変数をセットすることで、カスタマイズできます。 207cea338a 2010-11-26 kinaba: </p> 207cea338a 2010-11-26 kinaba: <pre> 207cea338a 2010-11-26 kinaba: >> @macro twice(x) { x; x } in twice(print("Hello")) 207cea338a 2010-11-26 kinaba: Hello 207cea338a 2010-11-26 kinaba: Hello 207cea338a 2010-11-26 kinaba: Hello 207cea338a 2010-11-26 kinaba: </pre> 207cea338a 2010-11-26 kinaba: <p> 207cea338a 2010-11-26 kinaba: (3回出力されてますが、3個目は <tt>print(x)</tt> の返値は <tt>x</tt> なので、 207cea338a 2010-11-26 kinaba: それがREPLによって印字されているだけです。) 207cea338a 2010-11-26 kinaba: <tt>@macro</tt> レイヤで <tt>in</tt> 以降を実行すると、<tt>print("Hello")</tt> という式を表す構文木が作られ、 207cea338a 2010-11-26 kinaba: それが <tt>twice</tt> 関数に渡されます。<tt>twice</tt> の中身も <tt>@macro</tt> レイヤで実行されるので、 207cea338a 2010-11-26 kinaba: 構文木を作ろうとしますが、変数 <tt>x</tt> には <tt>@macro</tt> レイヤで値が入っているので、 207cea338a 2010-11-26 kinaba: その値を読み取って構文木を作成します。 207cea338a 2010-11-26 kinaba: 結果として、2回 <tt>print("Hello")</tt> する構文木が作られて、 207cea338a 2010-11-26 kinaba: その後で、それが <tt>@value</tt> レイヤで実行されています。 207cea338a 2010-11-26 kinaba: </p> 207cea338a 2010-11-26 kinaba: <p> 207cea338a 2010-11-26 kinaba: 本当にベタに構文木を作るだけなので、変数名の衝突などなどは気にしません。「衛生的でない」マクロです。 207cea338a 2010-11-26 kinaba: </p> 207cea338a 2010-11-26 kinaba: <pre> 207cea338a 2010-11-26 kinaba: @macro LetItBe(x, y) { var $(B it) = x; y }; $(D_COMMENT # y の中で変数 it が使える) 207cea338a 2010-11-26 kinaba: print( LetItBe("myself", "when I find " ~ $(B it) ~ " in times of trouble") ); 207cea338a 2010-11-26 kinaba: </pre> 207cea338a 2010-11-26 kinaba: <p> 207cea338a 2010-11-26 kinaba: 変数名に気をつけるには、組み込み関数 <tt>gensym()</tt> を使って頑張って下さい。 207cea338a 2010-11-26 kinaba: </p> 207cea338a 2010-11-26 kinaba: )) 207cea338a 2010-11-26 kinaba: $(SECTION レイヤ切り替え, $(SECBODY 207cea338a 2010-11-26 kinaba: <p> 207cea338a 2010-11-26 kinaba: 他のレイヤ同様、<tt>@macro</tt> レイヤを実行中に <tt>@layer( ... )</tt> 構文を使うことで、 207cea338a 2010-11-26 kinaba: 別のレイヤでコードを動かすこともできます。よく使う例は、<tt>@value</tt> 207cea338a 2010-11-26 kinaba: レイヤに移ることで構文木を普通に計算して色々プログラム的にいじる用途です。 207cea338a 2010-11-26 kinaba: </p> c0158c9281 2010-11-24 kinaba: <pre> 207cea338a 2010-11-26 kinaba: @macro reverseArgs(e) {$(B @value)( 207cea338a 2010-11-26 kinaba: def rev(xs, acc) { 207cea338a 2010-11-26 kinaba: case xs when {car:x, cdr:xs}: rev(xs, {car:x, cdr:acc}) when {}: acc 207cea338a 2010-11-26 kinaba: }; 207cea338a 2010-11-26 kinaba: case @macro(e) 207cea338a 2010-11-26 kinaba: when {is:"App", fun:f, args:as}: {is:"App", fun:f, args:rev(as,{})} 207cea338a 2010-11-26 kinaba: when e: e 207cea338a 2010-11-26 kinaba: )}; 207cea338a 2010-11-26 kinaba: print( reverseArgs(1-2) ); $(D_COMMENT # 2-1 == 1) c0158c9281 2010-11-24 kinaba: </pre> 207cea338a 2010-11-26 kinaba: <p> 207cea338a 2010-11-26 kinaba: <tt>reverseArgs</tt> は、関数呼び出しの構文木の、引数の順番を逆転する関数です。 207cea338a 2010-11-26 kinaba: <tt>@macro(e)</tt> によってマクロレイヤにセットされている構文木引数を取り出し、 207cea338a 2010-11-26 kinaba: それを <tt>@value</tt> レイヤによる普通の計算プログラムで操作しています。 203e4cb208 2010-11-27 kinaba: <tt>@macro(...)</tt> はいわゆる「準クオート (quasiquote)」、 203e4cb208 2010-11-27 kinaba: <tt>@value(...)</tt> は「逆クオート (unquote)」にちょっと近いかもしれません。 207cea338a 2010-11-26 kinaba: </p> 207cea338a 2010-11-26 kinaba: <p> 207cea338a 2010-11-26 kinaba: <tt>@layer(...)</tt> だけでなく、関数のレイヤ指定引数なども同様に使うことができるので、 207cea338a 2010-11-26 kinaba: 一部の引数は <tt>@macro</tt>、一部の引数は <tt>@value</tt> レイヤで受け取る関数を書くなど、 207cea338a 2010-11-26 kinaba: さらに色々面白いことが可能です。 207cea338a 2010-11-26 kinaba: </p> 207cea338a 2010-11-26 kinaba: )) 207cea338a 2010-11-26 kinaba: $(SECTION 構文木の構造, $(SECBODY c0158c9281 2010-11-24 kinaba: <p> c0158c9281 2010-11-24 kinaba: 構文木がどのようなテーブルで渡されてくるかについては、ソースドキュメントの c0158c9281 2010-11-24 kinaba: <a href="http://www.kmonos.net/repos/polemy/doc/tip/doc/ast.html">polemy.ast</a> c0158c9281 2010-11-24 kinaba: のページをご覧下さい。例えば変数名を表す <code>Var</code> クラスには、 c0158c9281 2010-11-24 kinaba: 継承の分も合わせて c0158c9281 2010-11-24 kinaba: <tt><a href="http://www.kmonos.net/repos/polemy/doc/tip/doc/failure.html">LexPosition</a> pos;</tt> c0158c9281 2010-11-24 kinaba: と <tt>string name;</tt> の2つのメンバがあるので c0158c9281 2010-11-24 kinaba: </p> c0158c9281 2010-11-24 kinaba: <pre> c0158c9281 2010-11-24 kinaba: { is: "Var", c0158c9281 2010-11-24 kinaba: pos: {filename:"foo.pmy", lineno:123, column:45}, c0158c9281 2010-11-24 kinaba: name: "x" } c0158c9281 2010-11-24 kinaba: </pre> c0158c9281 2010-11-24 kinaba: <p> c0158c9281 2010-11-24 kinaba: こんな感じのテーブルになります。 c0158c9281 2010-11-24 kinaba: クラス名が <tt>is</tt> フィールドに、メンバ変数はそのままの名前で入ります。 c0158c9281 2010-11-24 kinaba: 配列メンバは cons リストになって入ってきます。 207cea338a 2010-11-26 kinaba: 自分で構文木を作る時は、<tt>pos</tt> フィールドだけは省略しても構いません。 207cea338a 2010-11-26 kinaba: </p> 207cea338a 2010-11-26 kinaba: )) 203e4cb208 2010-11-27 kinaba: $(SECTION 微妙なところ1, $(SECBODY 207cea338a 2010-11-26 kinaba: <p> 203e4cb208 2010-11-27 kinaba: ここまで、<tt>@macro</tt> が本当にただの1レイヤと説明してきましたが、 203e4cb208 2010-11-27 kinaba: 実はちょっとトリックが潜んでいます。 207cea338a 2010-11-26 kinaba: </p> 207cea338a 2010-11-26 kinaba: <pre> 207cea338a 2010-11-26 kinaba: >> @macro twice(x) {x; x} in twice($(B @value)(print("Hello"))) 207cea338a 2010-11-26 kinaba: Hello 207cea338a 2010-11-26 kinaba: Hello 207cea338a 2010-11-26 kinaba: Hello 207cea338a 2010-11-26 kinaba: </pre> 207cea338a 2010-11-26 kinaba: <p> 207cea338a 2010-11-26 kinaba: 先ほどの例に <tt>@value</tt> を増やしたものですが、これでもやはり、Hello 203e4cb208 2010-11-27 kinaba: が2回 print されるようになります。これは本来はおかしな話で、<tt>print("Hello")</tt> 203e4cb208 2010-11-27 kinaba: は <tt>@value</tt> レイヤで実行されて値に落ちるはずなので、1回しか print されないはず。 203e4cb208 2010-11-27 kinaba: </p> 203e4cb208 2010-11-27 kinaba: <p> 203e4cb208 2010-11-27 kinaba: 実は、Polemy の中では、<tt>@macro</tt> レイヤと <tt>(rawmacro)</tt> 203e4cb208 2010-11-27 kinaba: レイヤという二つの異なるマクロ用レイヤが動いています。 203e4cb208 2010-11-27 kinaba: </p> 203e4cb208 2010-11-27 kinaba: <ul> 203e4cb208 2010-11-27 kinaba: <li><tt>(rawmacro)</tt> も <tt>@macro</tt> も、コードを動かすとその構文木を返す意味論。</li> 203e4cb208 2010-11-27 kinaba: <li>ただし、<tt>(rawmacro)</tt> も <tt>@macro</tt> も、 203e4cb208 2010-11-27 kinaba: <tt>@macro</tt> レイヤに値のセットされた変数をみつけたときは、 203e4cb208 2010-11-27 kinaba: その変数という構文木を作るのではなく、変数の内容を展開。</li> 203e4cb208 2010-11-27 kinaba: <li>また <tt>@macro</tt> は、 203e4cb208 2010-11-27 kinaba: レイヤ指定式を見ると実行レイヤを切り替て、構文木生成モードをやめてしまう。</li> 203e4cb208 2010-11-27 kinaba: <li><tt>(rawmacro)</tt> は、 203e4cb208 2010-11-27 kinaba: レイヤ指定式を見ても実行レイヤを切り替えないで構文木にする。</li> 203e4cb208 2010-11-27 kinaba: </ul> 203e4cb208 2010-11-27 kinaba: <p> 203e4cb208 2010-11-27 kinaba: ユーザーから直接 <tt>(rawmacro)</tt> は呼べませんが、 203e4cb208 2010-11-27 kinaba: 「関数やトップレベル実行開始前のマクロ処理は <tt>(rawmacro)</tt> で実行開始」 203e4cb208 2010-11-27 kinaba: 「<tt>@macro</tt> レイヤ以外で呼び出した関数の仮引数に <tt>@macro</tt> がついていたら、 203e4cb208 2010-11-27 kinaba: その実引数は <tt>(rawmacro)</tt> で実行」 203e4cb208 2010-11-27 kinaba: という2つのタイミングで <tt>(rawmacro)</tt> が動き出します。 203e4cb208 2010-11-27 kinaba: <tt>(rawmacro)</tt> が <tt>@macro</tt> レイヤから変数を見つけてマクロし始める時に、 203e4cb208 2010-11-27 kinaba: そこで <tt>@macro</tt> に動作が移ります。 203e4cb208 2010-11-27 kinaba: </p> 203e4cb208 2010-11-27 kinaba: <p> 203e4cb208 2010-11-27 kinaba: こうなっているのは、全部がレイヤ指定式に反応する <tt>@macro</tt> の動作だと、 203e4cb208 2010-11-27 kinaba: レイヤを使ったプログラムが全て <tt>@value</tt> 実行時ではなく、 203e4cb208 2010-11-27 kinaba: マクロ展開の時点で動き始めてしまって、おかしなことになるためです。 203e4cb208 2010-11-27 kinaba: 色々考えた結果、とりあえずこの中途半端な混合が具合がよいのではないかということになりました。 203e4cb208 2010-11-27 kinaba: </p> 203e4cb208 2010-11-27 kinaba: )) 203e4cb208 2010-11-27 kinaba: $(SECTION 微妙なところ2, $(SECBODY 203e4cb208 2010-11-27 kinaba: <p> 203e4cb208 2010-11-27 kinaba: 「関数実行開始時に、まずマクロレイヤを実行」と書きましたが、この時、関数内関数まで辿りにいくので、 203e4cb208 2010-11-27 kinaba: 何重にもネストした関数を使っていると、内側の関数は、何重にもマクロ展開が走ってしまいます。 203e4cb208 2010-11-27 kinaba: これはなにかおかしい気がしますね。Scheme などはどうなっているのか調べないと…。 203e4cb208 2010-11-27 kinaba: </p> 203e4cb208 2010-11-27 kinaba: )) 203e4cb208 2010-11-27 kinaba: $(SECTION 微妙なところ3, $(SECBODY 203e4cb208 2010-11-27 kinaba: <p> 203e4cb208 2010-11-27 kinaba: これはエラーになります。 207cea338a 2010-11-26 kinaba: </p> 8caee17864 2010-11-24 kinaba: <pre> 203e4cb208 2010-11-27 kinaba: >> let _ = (@macro twice(x) {x;x} in twice(print("Hello"))) 203e4cb208 2010-11-27 kinaba: polemy.failure.RuntimeException@C:\Develop\Projects\Polemy\polemy\value.d(109): 203e4cb208 2010-11-27 kinaba: [<REPL>:2:35] 'twice' is not set in @value layer 20be503cae 2010-11-24 kinaba: </pre> 203e4cb208 2010-11-27 kinaba: <p> 203e4cb208 2010-11-27 kinaba: どういうことかというと、<tt>@macro</tt> で定義したマクロはいつから使えるようになるかという話で、 203e4cb208 2010-11-27 kinaba: この <tt>@macro twice(x) {x;x} in ...</tt> の部分は <tt>@value</tt> レイヤの式なので、 203e4cb208 2010-11-27 kinaba: まずこの式全体のマクロ展開が終わったあとにしか実行されないのです。<tt>twice</tt> 203e4cb208 2010-11-27 kinaba: がマクロと見なされはじめるのは、<tt>@macro</tt> 実行が終わった後。 203e4cb208 2010-11-27 kinaba: なので、 203e4cb208 2010-11-27 kinaba: 例えば <tt>twice(print("Hello"))</tt> の部分を無名関数にラップしてやれば、 203e4cb208 2010-11-27 kinaba: マクロ展開を遅らせられて、 ちゃんと実行ができます。 203e4cb208 2010-11-27 kinaba: </p> 203e4cb208 2010-11-27 kinaba: <p> 203e4cb208 2010-11-27 kinaba: これだと余りにも不便なので、関数のトップレベルの変数宣言式の列についてだけは、 203e4cb208 2010-11-27 kinaba: <tt>@macro</tt> と <tt>@value</tt> の評価を交互にインターリーブするようにしました。 203e4cb208 2010-11-27 kinaba: 「関数やREPLのトップレベルの最初に宣言したマクロだけは、その関数内で即座に使える」わけです。 203e4cb208 2010-11-27 kinaba: これも Scheme の let-syntax などなどの動きを調べて勉強しないと…。 203e4cb208 2010-11-27 kinaba: </p> 8caee17864 2010-11-24 kinaba: )) 8caee17864 2010-11-24 kinaba: ) 20be503cae 2010-11-24 kinaba: )) 20be503cae 2010-11-24 kinaba: 20be503cae 2010-11-24 kinaba: 20be503cae 2010-11-24 kinaba: $(SECTION Built-in Primitives, $(SECBODY 20be503cae 2010-11-24 kinaba: <p> 20be503cae 2010-11-24 kinaba: 組み込み関数・変数の一覧。 20be503cae 2010-11-24 kinaba: </p> 20be503cae 2010-11-24 kinaba: $(DDOC_MEMBERS 20be503cae 2010-11-24 kinaba: 20be503cae 2010-11-24 kinaba: $(SECTION テーブル操作, $(SECBODY 20be503cae 2010-11-24 kinaba: $(TABLE 20be503cae 2010-11-24 kinaba: $(TR $(TH {}) $(TD ()) $(TD 空のテーブルを作る)) 20be503cae 2010-11-24 kinaba: $(TR $(TH .) $(TD (t, s)) $(TD テーブル t の名前 s のフィールドの値を取得。なければ <tt>undefined</tt>)) 20be503cae 2010-11-24 kinaba: $(TR $(TH .?) $(TD (t, s)) $(TD テーブル t に名前 s のフィールドがあれば 1、なければ 0)) 20be503cae 2010-11-24 kinaba: $(TR $(TH .=) $(TD (t, s, v)) $(TD テーブル t を親に持ち、名前 s のフィールドに v が入ったテーブルを作る)) 20be503cae 2010-11-24 kinaba: ) 20be503cae 2010-11-24 kinaba: )) 20be503cae 2010-11-24 kinaba: <br /> 20be503cae 2010-11-24 kinaba: 20be503cae 2010-11-24 kinaba: $(SECTION 制御フロー, $(SECBODY 20be503cae 2010-11-24 kinaba: $(TABLE 20be503cae 2010-11-24 kinaba: $(TR $(TH if) $(TD (n, ft, fe)) $(TD n が非 0 なら <tt>ft()</t>、0 なら <tt>fe()</tt> を実行)) 20be503cae 2010-11-24 kinaba: ) 20be503cae 2010-11-24 kinaba: )) 20be503cae 2010-11-24 kinaba: <br /> 20be503cae 2010-11-24 kinaba: 20be503cae 2010-11-24 kinaba: $(SECTION 演算, $(SECBODY 20be503cae 2010-11-24 kinaba: $(TABLE 20be503cae 2010-11-24 kinaba: $(TR $(TH +) $(TD (n, m)) $(TD 整数 n と整数 m を足して返す)) 20be503cae 2010-11-24 kinaba: $(TR $(TH -) $(TD (n, m)) $(TD 整数の引き算)) 20be503cae 2010-11-24 kinaba: $(TR $(TH *) $(TD (n, m)) $(TD 整数の掛け算)) 20be503cae 2010-11-24 kinaba: $(TR $(TH /) $(TD (n, m)) $(TD 整数の割り算)) 20be503cae 2010-11-24 kinaba: $(TR $(TH %) $(TD (n, m)) $(TD 整数の剰余)) 20be503cae 2010-11-24 kinaba: $(TR $(TH &&) $(TD (n, m)) $(TD 整数 n と m が両方非 0 なら 1、それ以外では 0)) 20be503cae 2010-11-24 kinaba: $(TR $(TH ||) $(TD (n, m)) $(TD 整数 n と m がどちらか非 0 なら 1、それ以外では 0)) 20be503cae 2010-11-24 kinaba: $(TR $(TH ~) $(TD (a, b)) $(TD a と b を文字列化して結合)) 20be503cae 2010-11-24 kinaba: $(TR $(TH <) $(TD (a, b)) $(TD a と b を比較)) 20be503cae 2010-11-24 kinaba: $(TR $(TH <=) $(TD (a, b)) $(TD a と b を比較)) 20be503cae 2010-11-24 kinaba: $(TR $(TH >) $(TD (a, b)) $(TD a と b を比較)) 20be503cae 2010-11-24 kinaba: $(TR $(TH >=) $(TD (a, b)) $(TD a と b を比較)) 20be503cae 2010-11-24 kinaba: $(TR $(TH ==) $(TD (a, b)) $(TD a と b を比較)) 20be503cae 2010-11-24 kinaba: $(TR $(TH !=) $(TD (a, b)) $(TD a と b を比較)) 20be503cae 2010-11-24 kinaba: ) 20be503cae 2010-11-24 kinaba: <p> 20be503cae 2010-11-24 kinaba: 注意点として、作者の趣味の問題で、<tt>&&</tt> と <tt>||</tt> は short-circuit 評価をしません。 20be503cae 2010-11-24 kinaba: 整数演算の種類が少ないのは、D 言語の std.bigint がビット演算などをサポートしてないためです。 20be503cae 2010-11-24 kinaba: 文字列が結合しかできないのは、単に手抜きです。 20be503cae 2010-11-24 kinaba: </p> 20be503cae 2010-11-24 kinaba: )) 20be503cae 2010-11-24 kinaba: 20be503cae 2010-11-24 kinaba: $(SECTION 外部とのやりとり, $(SECBODY 20be503cae 2010-11-24 kinaba: $(TABLE 474c4facf0 2010-11-25 kinaba: $(TR $(TH print) $(TD (a)) $(TD a を文字列化標準出力に改行付きで表示して、a を返す)) 20be503cae 2010-11-24 kinaba: $(TR $(TH argv) $(TD ) $(TD スクリプトに渡された引数文字列のconsリスト)) c75f0d5f1e 2010-11-24 kinaba: $(TR $(TH gensym) $(TD ()) $(TD エセgensym。変数名として他とかぶらなそうな文字列を返します)) f9c31f3cd8 2010-11-24 kinaba: $(TR $(TH rand) $(TD (n)) $(TD 0 以上 n 未満の自然数を31bit以内でランダムに生成します)) 20be503cae 2010-11-24 kinaba: ) 20be503cae 2010-11-24 kinaba: )) 20be503cae 2010-11-24 kinaba: <br /> 20be503cae 2010-11-24 kinaba: 20be503cae 2010-11-24 kinaba: $(SECTION データ型判定, $(SECBODY 20be503cae 2010-11-24 kinaba: $(TABLE 20be503cae 2010-11-24 kinaba: $(TR $(TH _isint) $(TD (a)) $(TD a が整数なら 1、でなければ 0)) 20be503cae 2010-11-24 kinaba: $(TR $(TH _isstr) $(TD (a)) $(TD a が文字列なら 1、でなければ 0)) 20be503cae 2010-11-24 kinaba: $(TR $(TH _isfun) $(TD (a)) $(TD a が関数なら 1、でなければ 0)) 005474ba5b 2010-11-27 kinaba: $(TR $(TH _istbl) $(TD (a)) $(TD a がテーブルなら 1、でなければ 0)) 005474ba5b 2010-11-27 kinaba: $(TR $(TH _isbot) $(TD (a)) $(TD a が未定義値なら 1、でなければ 0)) 20be503cae 2010-11-24 kinaba: ) 20be503cae 2010-11-24 kinaba: )) 20be503cae 2010-11-24 kinaba: ) 20be503cae 2010-11-24 kinaba: )) 20be503cae 2010-11-24 kinaba: 20be503cae 2010-11-24 kinaba: ) 20be503cae 2010-11-24 kinaba: Macros: 20be503cae 2010-11-24 kinaba: TITLE=Polemy Reference Manual 20be503cae 2010-11-24 kinaba: DOCFILENAME=index.html 20be503cae 2010-11-24 kinaba: SECTION=$(DDOC_DECL $(DDOC_PSYMBOL $1)) $(DDOC_DECL_DD $2) 20be503cae 2010-11-24 kinaba: SECBODY=$0