述語のdestruct
これ見る人いるのかな・・・
昨日の話と全然連続しないが、昨日のシリーズの続き。
Propに属する帰納型(以下、述語と記述)の展開の話。
Coqのマニュアルだとここの4.5.4のAllowed elimination sortsのあたり。
実際のところ、使用者からして気になる部分はそう多くなくて、大体がこの部分。
しかし、非常に読みにくい。
というわけで簡単な説明をする。
destructといいながら、Curry-Howard対応から実際にはパターンマッチなのでこちらを使う。
内容は、パターンマッチで述語を場合分けすると、ある特定の場合にできない場合がある、というもの。
ちなみにSetやTypeに属する帰納型ではどんなものでも返せる。
さて、特定の場合、と言っているがどんな場合かと言うと、返す値が述語じゃないときである。
逆に言うと述語ならOK。SetとかTypeとか(述語でない)型自体とか全部ダメ。
この理由は、proof irrelevanceという考え方から来ている。
まあ、問題を見るにはextractionを考えればいい。
Proof irrelevanceは、簡単に言うと「証明なんてプログラムと関係ないんだから、プログラムとしては無視して問題ないよね?」ということ。
顕著な例がextraction。Coqから別の言語のコードに変換すること。
証明はきれいさっぱり消えるし、依存型も述語部分が消える。
いやはや、なかなか良くできている。
だが、消えるのだから困ることもある。
こんなプログラムが書けたらどうなるだろう?
fun x : or P Q => match x with | or_intror _ => true | or_introl _ => false end
trueやfalseはbool型、boolはSet。orはProp。
さて、extractionするとどうなる?
- 関数の引数xは消える。or P Qが述語だから。
- trueやfalseは消えない。boolはSetだから。
で、何が出る?関数じゃないことはわかるが、true?false?
つまりはこれがまずい、ということである。*1 *2 *3
だが、この問題、実は例外があって・・・
と言っても長くなるのでまた今度。
実は例外がないとそれはそれで困るのだ。*4
補足:inversionやinduction
ちょっと説明してないのもどうかと思ったので。
述語のdestructの話は、計算レベルで制限されている話で、問題になりやすいのはinversionやinductionだと思う(inductionはかなり稀か)。
「ゴールがSetやTypeに属する型であるときに、述語をinversionしたら怒られた」という経験がある人もいるだろう。
実はこれもまったく同じ原因である。
というのも、tacticは一般に関数や項を作るからだ。
introやapplyのように簡単なtacticは対応する項も割と簡単(関数抽象・関数適用)である。
一方、inversionは結構小難しいことをする。
しかし、小難しいことをしようが何をしようが*1必ず結果は項を作る。
そしてinversionはパターンマッチを作る。
だから怒られる。
inductionは実際には特定の関数をゴールに適用する。
しかし、その関数がパターンマッチを使うため、SetやTypeを返す関数が作成できない。
だから無理、と。
つまりは、根源はすべてパターンマッチができないことである、ということ。
*1:admitでもしない限り。