記法を定義出来る (2)
• 単項演算子、mix-fixな演算子もOK: かなりDSLっぽくなる
Notation "~ x" := (not x) (at level 75, right associativity).
Notation "’IF’ c1 ’then’ c2 ’else’ c3" :=
(IF_then_else c1 c2 c3).
Notation "{ x : A | P }” := (sigA (fun x => P))
(at level 0, x at level 99).
• 推論して欲しい場合は@を付けないと(使用時に)エラー
Notation "x = y" := (@eq _ x y) (at level 70, no associativity).
• 定義と一緒に記法を定義出来る
Fixpoint plus (n m:nat) {struct n} : nat :=
match n with
| O => m
| S p => S (p+m)
end
where "n + m" := (plus n m).
11
12.
記法を定義出来る (3)
• パーサコンビネータと組み合わせて使っている例
http://www.seas.upenn.edu/~cis500/current/sf/html/ImpParser.html
Notation“‘DO’ ( x , y ) <-- e1 ;; e2 ‘OR’ e3” :=
(match e1 with
| SomeE (x,y) => e2
| NoneE err => e3
end) (right associativity, at level 60, e2 at next level).
• 使っている例
Fixpoint parsePrimaryExp (steps:nat) symtable (xs : list token)
: optionE (aexp * list token) :=
match steps with
| 0 => NoneE "Too many recursive calls"
| S steps' =>
DO (i, rest) <-- parseIdentifier symtable xs ;;
SomeE (AId i, rest)
OR DO (n, rest) <-- parseNumber xs ;;
SomeE (ANum n, rest)
OR (DO (e, rest) <== firstExpect "(" (parseSumExp steps' symtable) xs;;
DO (u, rest') <== expect ")" rest ;;
SomeE(e,rest'))
end 12
13.
記法を定義出来る (4)
• 繰り返しのあるパターン: .. を使って繰り返しを再帰的に表現出来る
– 可変長引数みたいなものを扱いたいときは便利
Coq < Notation "[ x ; .. ; y ]" :=
(@cons _ x .. (@cons _ y (@nil _) ) .. ).
Setting notation at level 0.
Coq < Check ([1 ; 2 ; 3]).
[1; 2; 3]
: list nat
• 実は下記でもOK
Coq < Notation "[ x ; .. ; y ]" := (cons x .. (cons y nil) ..).
Setting notation at level 0.
13
14.
記法定義の落とし穴
• えっ?定義が無いの?本当?
Coq <Locate "->".
Unknown notation
• 定義出来た!?
Notation "A -> B" := (and A B) (at level 80, right associativity).
• 本当に定義が上書きされたのか?
Coq < Lemma test : True -> True.
test < intros.
1 subgoal
============================
True -> True (* 変化が無い *)
test < split.
2 subgoals
============================
True (* and なので split される *)
subgoal 2 is:
True
• Locate信用出来ない。重要な予約語の上書きには注意。 14
15.
Tacticの定義の方法
CPDTに載っているTactic定義の例 (p.217)
Coq <Ltac my_tauto :=
Coq < repeat match goal with
Coq < | [ H : ?P |- ?P ] => exact H
Coq < | [ |- True ] => constructor
Coq < | [ |- _ / _ ] => constructor
Coq < | [ |- _ -> _ ] => intro
Coq < | [ H : False |- _ ] => destruct H
Coq < | [ H : _ / _ |- _ ] => destruct H
Coq < | [ H : _ / _ |- _ ] => destruct H
Coq < | [ H1 : ?P -> ?Q, H2 : ?P |- _ ] =>
Coq < let H := fresh “H” in (* Hなんとかみたいな新しい名前をつける *)
Coq < generalize (H1 H2); clear H1; intro H
Coq < end.
my_tauto is defined
repeatを外したmy_tauto1を作って、何度も適用すると動作の具合が良く解る
…これって、DSLに使えない?
• パターンマッチとかどう見ても高機能なんだが…
15