Commits

camlspotter committed 40c5f6f

enriched about quotation glitches

Comments (0)

Files changed (1)

 
 ということだ。実際のところ Revised syntax は Original syntax と比べて人間の目には冗長に見える。Original syntax を知っている人には違いを覚えるのも大変である。
 
-Revised syntax が有利になるのは P4 での拡張を *Quotation* (*Quote* 後述) を使って書く場合だけである。言語の枠構造などが人間に優しく省略されている Original syntax では、 Quote を使って拡張を書く場合境界がはっきりせずうまく書けない場合がある。Revised は P4 のための DSL として作られており、そのような境界が明示されているので書きやすい。
+Revised syntax が有利になるのは P4 での拡張を *Quotation* (*Quote* 後述) を使って書く場合だけである。
+Revised は P4 のための DSL として作られており、枠構造が明確になっており Quote が書きやすい場合がある。
 
-では Revised syntax を習得するべきか。 **否。Revised syntax は無視してよろしい。というか無視しろ。** この文法は P4 でしか役に立たないので覚えるのは時間の無駄である。Original syntax では Quote が書けなくなるじゃないですか…という人には、Quote を使わなくても P4 は書ける、と答えよう。Revised syntax でうんうん唸るなら書けない、書きにくい Quote が現れたらそこはベタに AST コンストラクタを書く(*生書き*)。もちろん Quote が書けてそちらの方が簡便な場合は Quote を使おう。Revised syntax は何となく読めればよい。それが近道だ。
+では Revised syntax を習得するべきか。 **否。Revised syntax は無視してよろしい。というか無視しろ。** 
+この文法は P4 でしか役に立たないので覚えるのは時間の無駄である。Original syntax では Quote が書けなくなるじゃないですか…という人には、
+Quote を使わなくても P4 は書ける、と答えよう。
+Revised syntax でうんうん唸るなら書けない、書きにくい Quote が現れたらそこはベタに AST コンストラクタを書く(*生書き*)。
+もちろん Quote が書けてそちらの方が簡便な場合は Quote を使おう。Revised syntax は何となく読めればよい。それが近道だ。
+
 
 camlp4, camlp4o, camlp4of, camlp4oof, camlp4orf, camlp4r,  camlp4rf … ナメてんのか!
 ======================================================================================
 $ が Anti-quote のために予約されているため $ は使えなくなってしまう。なので $ を OCaml で
 使うのは避けよとは言わないが、注意しておくべし。
 
+演習問題
+-------------
+まだ書いてない。
+
 Original syntax ではうまく書けない Quotation
 ================================================
 
+なぜ Original と Revised syntax という二つの文法があるのか、
+それは Original syntax だと Quotation がうまく書けない場合があるからだ。
+次の sig ... end のためのコンストラクタを見てみよう::
+
+      (* sig sg end *)
+    | MtSig of loc and sig_item
+
+さて、これを使って sig .. end にマッチするパターン MtSig(_loc, sg) なのだが、
+これに相当する Quotation を書こうとすると…書けない。::
+
+    <:module_type< sig $sg$ end >>
+
+は::
+
+    Ast.MtSig (_loc, (Ast.SgSem (_loc, y, (Ast.SgNil _loc))))
+
+に展開される。なんですかこの SgNil は?!?
+Revised syntax ならば::
+
+    value x = <:module_type< sig $sg$ end >>;
+
+は camlp4rf を使えばちゃんと::
+
+    let x = Ast.MtSig (_loc, sg)
+
+に展開されるのに…
+
+ここに Original syntax にこだわると Quotation で難儀する原因がある。
+**Original syntax の Quote は、いくつかのリストの形をした AST コンストラクタを最小の形で記述することができないのだ。** 
+これは治せるバグなのかどうかは判らない、というか調べたら多分戻ってこれないので調べてない。
+
+さて、これがすごく問題かというとそうでもない。
+パターンと同様、式においても Quotation <:module_type<sig $x$ end>> は
+SgNil のある式に展開されるし、 camlp4of が sig .. end という OCaml ソースを
+読み込んだ時もやはりこの SgNil が最後にくっついてくるからだ。(多分。希望である。)
+
+これが原因で Original syntax で module_type の Quote を使ったパターンマッチを書くと
+Ast.MtSig (_, _) のケースが押さえることが出来ず non exhaustive になってしまう。
+これが気になる場合はデフォルトケースでエラーにするか、Quote を使わず MtSig のケースを生書きするか、
+ともかくちょっとした工夫が必要になる。
+
 例題: 定義された型を抜き出す
 =================================
 
-執筆途中
-
 OCaml のインターフェースファイル mli の P4 でのパースツリーの型は sig_item という
 型である。(Camlp4Ast 参照) この型の値を受け取り、 mli 内部で定義されている型の名前の
 文字列を全て抜き出したい。sig_item -> string list という型を持つ
-関数 extract_defined_type_names を作成せよ
+関数 extract_defined_type_names を作成する
 
 これを実直にやるならば単に sig_item の型の定義を見ながらパターンマッチを
 行なって全てのノードを辿る関数を書くだけ。普通にトラバーサルして末尾再帰::
         
       let extract_defined_type_names sg = 
         let rec ext_sig_item st = function
-          | <:sig_item< >>                             -> st
-          | <:sig_item< class $_$ >>                   -> st
-          | <:sig_item< class type $_$ >>              -> st
-          | <:sig_item< $sg1$ $sg2$ >>                 -> List.fold_left ext_sig_item st [sg1; sg2]
-          | <:sig_item< #$_$ >>                        -> st
-          | <:sig_item< exception $_$ >>               -> st
-          | <:sig_item< external $_$ >>                -> st
-          | <:sig_item< include $_$ >>                 -> st
-          | <:sig_item< module $m$ : $mty$ >>      -> ext_module_type st mty
+          | <:sig_item<                             >> -> st
+          | <:sig_item< class $_$                   >> -> st
+          | <:sig_item< class type $_$              >> -> st
+          | <:sig_item< $sg1$ $sg2$                 >> -> List.fold_left ext_sig_item st [sg1; sg2]
+          | <:sig_item< #$_$                        >> -> st
+          | <:sig_item< exception $_$               >> -> st
+          | <:sig_item< external $_$                >> -> st
+          | <:sig_item< include $_$                 >> -> st
+          | <:sig_item< module $m$ : $mty$          >> -> ext_module_type st mty
           | <:sig_item< module rec $module_binding$ >> -> ext_module_binding st module_binding
-          | <:sig_item< module type $_$ = $_$ >>       -> st
-          | <:sig_item< open $_$ >>                    -> st
-          | <:sig_item< type $ctyp$ >>                 -> ext_ctyp st ctyp
-          | <:sig_item< val $_$ >>                     -> st
-          | Ast.SgAnt _                                -> assert false
-        and ext_module_type _ _ = assert false
-        and ext_module_binding _ _ = assert false
-        and ext_ctyp _ _ = assert false
+          | <:sig_item< module type $_$ = $_$       >> -> st
+          | <:sig_item< open $_$                    >> -> st
+          | <:sig_item< type $ctyp$                 >> -> ext_ctyp st ctyp
+          | <:sig_item< val $_$                     >> -> st
+          | Ast.SgAnt _                                    -> assert false
+        and ext_module_type _ _ = assert false    (* 未実装 *)
+        and ext_module_binding _ _ = assert false (* 未実装 *)
+        and ext_ctyp _ _ = assert false           (* 未実装 *)
         in
         ext_sig_item [] sg
     
     File "pa_extract_types.ml.ml", line 26, characters 19-19:
     Warning 11: this match case is unused.
 
-ほにゃにゃにゃー今度はパターンが完全に埋まっていないですと言われた。SgDir だからこの部分だ::
+今度はパターンが完全に埋まっていないですと言われた。SgDir だからこの部分だ::
 
       | <:sig_item< #$_$ >>                        -> st