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: 203e4cb208 2010-11-27 kinaba: $(SECTION Layers, $(SECBODY a795c97dc3 2010-11-27 kinaba: <p> a795c97dc3 2010-11-27 kinaba: この言語の唯一の特徴的な部分は、「レイヤ」機能です。 a795c97dc3 2010-11-27 kinaba: </p> a795c97dc3 2010-11-27 kinaba: $(DDOC_MEMBERS a795c97dc3 2010-11-27 kinaba: $(SECTION Layers, $(SECBODY 20be503cae 2010-11-24 kinaba: <pre> 20be503cae 2010-11-24 kinaba: [Layers :: Overview] 20be503cae 2010-11-24 kinaba: 20be503cae 2010-11-24 kinaba: Polemy's runtime environment has many "layer"s. 20be503cae 2010-11-24 kinaba: Usual execution run in the @value layer. 20be503cae 2010-11-24 kinaba: 20be503cae 2010-11-24 kinaba: >> 1 + 2 20be503cae 2010-11-24 kinaba: 3 20be503cae 2010-11-24 kinaba: >> @value( 1 + 2 ) 20be503cae 2010-11-24 kinaba: 3 20be503cae 2010-11-24 kinaba: 20be503cae 2010-11-24 kinaba: Here you can see that @LayerName( Expression ) executes the inner Expression in 20be503cae 2010-11-24 kinaba: the @LayerName layer. Other than @value, one other predefined layer exists: @macro. 20be503cae 2010-11-24 kinaba: 20be503cae 2010-11-24 kinaba: >> @macro( 1+2 ) 20be503cae 2010-11-24 kinaba: {pos@value:{lineno@value:3, column@value:9, filename@value:<REPL>}, 20be503cae 2010-11-24 kinaba: is@value:app, 20be503cae 2010-11-24 kinaba: args@value:{car@value:{pos@value:{lineno@value:3, column@value:9, filename@value:<REPL>}, 20be503cae 2010-11-24 kinaba: is@value:int, 20be503cae 2010-11-24 kinaba: data@value:1}, 20be503cae 2010-11-24 kinaba: cdr@value:{ 20be503cae 2010-11-24 kinaba: car@value:{pos@value:{lineno@value:3, column@value:11, filename@value:<REPL>}, 20be503cae 2010-11-24 kinaba: is@value:int, 20be503cae 2010-11-24 kinaba: data@value:2}, 20be503cae 2010-11-24 kinaba: cdr@value:{}}}, 20be503cae 2010-11-24 kinaba: fun@value:{pos@value:{lineno@value:3, column@value:10, filename@value:<REPL>}, 20be503cae 2010-11-24 kinaba: is@value:var, 20be503cae 2010-11-24 kinaba: name@value:+}} 20be503cae 2010-11-24 kinaba: 20be503cae 2010-11-24 kinaba: (Sorry, this pretty printing is not available on the actual interpreter...) 20be503cae 2010-11-24 kinaba: This evaluates the expression 1+2 in the @macro layer. In this layer, the meaning of 20be503cae 2010-11-24 kinaba: the program is its abstract syntax tree. 20be503cae 2010-11-24 kinaba: 20be503cae 2010-11-24 kinaba: You can interleave layers. 20be503cae 2010-11-24 kinaba: The root node of the abstract syntax tree is function "app"lication. 20be503cae 2010-11-24 kinaba: 20be503cae 2010-11-24 kinaba: >> @value(@macro( 1+2 ).is) 20be503cae 2010-11-24 kinaba: app 20be503cae 2010-11-24 kinaba: 20be503cae 2010-11-24 kinaba: 20be503cae 2010-11-24 kinaba: 20be503cae 2010-11-24 kinaba: [Layers :: Defining a new layer] 20be503cae 2010-11-24 kinaba: 20be503cae 2010-11-24 kinaba: To define a new layer, you should first tell how to "lift" existing values two the new layer. 20be503cae 2010-11-24 kinaba: Let us define the "@type" layer, where the meaning of programs is their static type. 20be503cae 2010-11-24 kinaba: 20be503cae 2010-11-24 kinaba: >> @@type = fun(x) { 20be503cae 2010-11-24 kinaba: >> if( _isint(x) ) { "int" } else { 20be503cae 2010-11-24 kinaba: >> if( _isfun(x) ) { x } else { "unknown" } } 20be503cae 2010-11-24 kinaba: >> } 20be503cae 2010-11-24 kinaba: (Note: polemy REPL may warn some exception here but please ignore) 20be503cae 2010-11-24 kinaba: 20be503cae 2010-11-24 kinaba: For simplicity, I here deal only with integers. 20be503cae 2010-11-24 kinaba: _isint is a primitive function of Polemy that checks the dynamic type of a value. 20be503cae 2010-11-24 kinaba: For function, leaving it untouched works well for almost all layers. 20be503cae 2010-11-24 kinaba: 20be503cae 2010-11-24 kinaba: >> @type( 1 ) 20be503cae 2010-11-24 kinaba: int 20be503cae 2010-11-24 kinaba: >> @type( 2 ) 20be503cae 2010-11-24 kinaba: int 20be503cae 2010-11-24 kinaba: >> @type( "foo" ) 20be503cae 2010-11-24 kinaba: unknown 20be503cae 2010-11-24 kinaba: 20be503cae 2010-11-24 kinaba: Fine! Let's try to type 1+2. 20be503cae 2010-11-24 kinaba: 20be503cae 2010-11-24 kinaba: >> @type( 1 + 2 ) 20be503cae 2010-11-24 kinaba: ...\value.d(119): [<REPL>:6:8] only @value layer can call native function 20be503cae 2010-11-24 kinaba: 20be503cae 2010-11-24 kinaba: Note that the behavior of this program is 20be503cae 2010-11-24 kinaba: - run 1+2 in the @type layer 20be503cae 2010-11-24 kinaba: and NOT 20be503cae 2010-11-24 kinaba: - run 1+2 in @value and obtain 3 and run 3 in the @type. 20be503cae 2010-11-24 kinaba: The problem is, the variable "+" is defined only in the @value layer. 20be503cae 2010-11-24 kinaba: To carry out computation in the @type layer. We need to define it also 20be503cae 2010-11-24 kinaba: in the @type layer. 20be503cae 2010-11-24 kinaba: 20be503cae 2010-11-24 kinaba: To define some variable in a specific layer, use @LayerName in place of 20be503cae 2010-11-24 kinaba: (let|var|def)s. 20be503cae 2010-11-24 kinaba: 20be503cae 2010-11-24 kinaba: >> let x = 2 20be503cae 2010-11-24 kinaba: >> @value x = 2 20be503cae 2010-11-24 kinaba: >> @type x = "int" 20be503cae 2010-11-24 kinaba: >> @hoge x = "fuga" 20be503cae 2010-11-24 kinaba: 20be503cae 2010-11-24 kinaba: For "+", do it like this. 20be503cae 2010-11-24 kinaba: 20be503cae 2010-11-24 kinaba: >> @type "+" = fun(x,y) {@value( 20be503cae 2010-11-24 kinaba: >> if( @type(x)=="int" && @type(y)=="int" ) { "int" } else { "typeerror" } 20be503cae 2010-11-24 kinaba: >> )} 20be503cae 2010-11-24 kinaba: polemy.value.native!(IntValue,IntValue,IntValue).native.__anonclass24 20be503cae 2010-11-24 kinaba: 20be503cae 2010-11-24 kinaba: It is just computing the return type from the input type. 20be503cae 2010-11-24 kinaba: Not here that the intended "meaning" of if-then-else is the runtime-branching, 20be503cae 2010-11-24 kinaba: and the meaning of "==" is the value-comparison. These are the @value layer 20be503cae 2010-11-24 kinaba: behavior. So we have defined the function body inside @value layer. 20be503cae 2010-11-24 kinaba: But when we refer the variables x and y, we need its @type layer meaning. 20be503cae 2010-11-24 kinaba: Hence we use @type() there. 20be503cae 2010-11-24 kinaba: 20be503cae 2010-11-24 kinaba: Now we get it. 20be503cae 2010-11-24 kinaba: 20be503cae 2010-11-24 kinaba: >> @type( 1 + 2 ) 20be503cae 2010-11-24 kinaba: int 20be503cae 2010-11-24 kinaba: 20be503cae 2010-11-24 kinaba: Well, but do we have to define the @type layer meaning for every variables??? 20be503cae 2010-11-24 kinaba: No. After you defined @type "+", you'll automatically get the following: 20be503cae 2010-11-24 kinaba: 20be503cae 2010-11-24 kinaba: >> def double(x) { x + x } 20be503cae 2010-11-24 kinaba: (function:17e4740:1789720) 20be503cae 2010-11-24 kinaba: 20be503cae 2010-11-24 kinaba: >> @type( double(123) ) 20be503cae 2010-11-24 kinaba: int 20be503cae 2010-11-24 kinaba: 20be503cae 2010-11-24 kinaba: Every user-defined functions are automatically "lift"ed to the appropriate layer. 20be503cae 2010-11-24 kinaba: Only primitive functions like "+" requires @yourNewLayer annotation. 20be503cae 2010-11-24 kinaba: 20be503cae 2010-11-24 kinaba: 20be503cae 2010-11-24 kinaba: 20be503cae 2010-11-24 kinaba: [Layers :: neutral-layer] 20be503cae 2010-11-24 kinaba: 20be503cae 2010-11-24 kinaba: let|var|def is to define a variable in the "current" layer. 20be503cae 2010-11-24 kinaba: Not necessary to the @value layer. 20be503cae 2010-11-24 kinaba: 20be503cae 2010-11-24 kinaba: >> @value( let x = 1 in @value(x) ) 20be503cae 2010-11-24 kinaba: 1 20be503cae 2010-11-24 kinaba: 20be503cae 2010-11-24 kinaba: >> @macro( let x = 1 in @value(x) ) 20be503cae 2010-11-24 kinaba: polemy.failure.RuntimeException: [<REPL>:14:29] variable x not found 20be503cae 2010-11-24 kinaba: 20be503cae 2010-11-24 kinaba: >> @macro( let x = 1 in @macro(x) ) 20be503cae 2010-11-24 kinaba: {pos@value:{lineno@value:15, ... 20be503cae 2010-11-24 kinaba: 20be503cae 2010-11-24 kinaba: 20be503cae 2010-11-24 kinaba: 20be503cae 2010-11-24 kinaba: [Layers :: Layered-Parameters] 20be503cae 2010-11-24 kinaba: 20be503cae 2010-11-24 kinaba: >> def foo(x @macro @value) { {fst: x, snd: @macro(x)} } 20be503cae 2010-11-24 kinaba: (function:1730360:1789720) 20be503cae 2010-11-24 kinaba: 20be503cae 2010-11-24 kinaba: If you annotate function parameters by @LayerNames, when you invoke the function... 20be503cae 2010-11-24 kinaba: 20be503cae 2010-11-24 kinaba: >> foo(1+2) 20be503cae 2010-11-24 kinaba: {snd@value: {pos@value:{lineno@value:17, column@value:5, filename@value:<REPL>}, 20be503cae 2010-11-24 kinaba: is@value:app, arg@value:{... 20be503cae 2010-11-24 kinaba: /fst@value:3 20be503cae 2010-11-24 kinaba: /} 20be503cae 2010-11-24 kinaba: 20be503cae 2010-11-24 kinaba: its corresponding arguments are evaluated in the layer and passed to it. 20be503cae 2010-11-24 kinaba: If you specify multiple layers, the argument expression is run multiple times. 20be503cae 2010-11-24 kinaba: If you do not specify any layer for a parameter, it works in the neutral layer. 8caee17864 2010-11-24 kinaba: </pre> a795c97dc3 2010-11-27 kinaba: )) a795c97dc3 2010-11-27 kinaba: ) 203e4cb208 2010-11-27 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: <pre> 8caee17864 2010-11-24 kinaba: (ここに例) 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: <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)) 20be503cae 2010-11-24 kinaba: $(TR $(TH _istable) $(TD (a)) $(TD a がテーブルなら 1、でなければ 0)) 20be503cae 2010-11-24 kinaba: $(TR $(TH _isundefined) $(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