修行失敗

割と良く分からないなーって感じになって、ググるとさかいさんの記事が出て来たので、依存和使っててすごいというか、なんで依存和使ってるか分からん感じだったんですけれども、実際やってみると少し分かりました。

http://www.tom.sfc.keio.ac.jp/~sakai/d/?date=20070810#p02

Id型の使いどころが面白くて

data Id {X : Set0} : X -> X -> Set0 where
  id : (x : X) -> Id x x

みたいな感じで定義出来て、これどうやって使うねん という感じだと思うんですが

same_val1 : Id (succ (succ zero)) (succ zero + succ zero)
same_val1 = id (succ (succ zero))

とか、これはまぁリテラルであからさま過ぎて、こういうあからさまなヤツにはAgda2さんは頑張ってしまうのでもうちょっとキツいヤツでもなんとかやってくれるんですけど、filterのproofの中だとあんまりキツいやつ使うと負けちゃうので・・・。

あと、このIdと依存和組み合わせた時は、これまた何か知らないんですけれどもfilterのproofの中でするする言っちゃうので、謎過ぎる・・・。

取りあえずAgda2で書き直したコードをべだり゛

module QSort4 where

open import Bool
open import Nat
open import List
open import ValueHolder

length : {A : Set0} -> List A -> Nat
length [] = zero
length (x :: xs) = succ (length xs)

-- 場合分けを避ける為に非常に簡単なfilterにしています
filter : {A : Set0} -> (A -> Bool) -> List A -> List A
filter p [] = []
filter p (x :: xs) = filter p xs

data Id {X : Set0} : X -> X -> Set0 where
  id : (x : X) -> Id x x

record Sum (X : Set0) (Y : X -> Set0) : Set0 where
  field
    pi1 : X
    pi2 : Y pi1

Exist : {D : Set0} -> (D -> Set0) -> Set0
Exist {Type} p = Sum Type p

LE : Nat -> Nat -> Set0
LE n m = Exist (λ x -> Id (x + n) m)

Smaller : {X : Set0} -> List X -> List X -> Set0
Smaller xs ys = LE (length xs) (length ys)

-- 安易に準公理を持って来ている私の頭の悪さ
postulate p_succId : {x : Nat} {y : Nat} -> Id x y -> Id (succ x) (succ y)
postulate tranId : {X : Set0} {a b c : X} -> Id a b -> Id b c -> Id a c

infixl 5 _<=>_

_<=>_ : {X : Set0} {x y z : X} -> Id x y -> Id y z -> Id x z
id1 <=> id2 = tranId id1 id2

filterproof : (p : Nat -> Bool) -> (xs : List Nat) -> Smaller (filter p xs) xs
filterproof p [] = record { pi1 = zero ; pi2 = id zero }
filterproof p (x :: xs') = record { pi1 = fst ; pi2 = snd }
  where
    hypo : Smaller (filter p xs') xs'
    hypo = filterproof p xs'
    n : Nat
    n = Sum.pi1 hypo
    fst : Nat
    fst = succ n
    lem1 : Id (n + length (filter p xs')) (length xs') -- まずこれが言えるっていう時点で...
    lem1 = Sum.pi2 hypo
    --lem1' : Id (n + length (filter p xs')) (length xs')
    --lem1' = -- id (length xs') -- id (n + length (filter p xs')) -- これらは出来ないらしい。面白い
    lem2 : Id ((succ n) + length (filter p (x :: xs'))) ((succ n) + length (filter p xs')) 
    lem2 = id ((succ n) + length (filter p xs'))
    lem3 : Id ((succ n) + length (filter p xs')) (succ (n + length (filter p xs')))
    lem3 = id (succ (n + length (filter p xs')))
    lem4 : Id (succ (n + length (filter p xs'))) (succ (length xs'))
    lem4 = p_succId lem1 -- (succId lem1) -- mapId succ lem1 -- p_succId lem1 -- (succId lem1)
    lem5 : Id (succ (length xs')) (length (x :: xs'))
    lem5 = id (length (x :: xs'))
    -- 全部くっ付ける
    snd : Id ((succ n) + length (filter p (x :: xs'))) (length (x :: xs'))
    snd = (id ((succ n) + length (filter p (x :: xs')))) <=>
          (id ((succ n) + length (filter p xs'))) <=>
          (id (succ (n + length (filter p xs')))) <=>
          (p_succId lem1) <=> (id (length (x :: xs')))
    
sort : List Nat -> List Nat
sort [] = []
sort (x :: xs) = sort first -- 残念です
  where
    pred1 : (Nat -> Bool)
    pred1 = (λ v -> x < v)
    first : List Nat
    first = filter pred1 xs
    useproof : Smaller (first) xs
    useproof = filterproof pred1 xs
    n : Nat
    n = Sum.pi1 useproof
    lem1 : Id (n + length first) (length xs)
    lem1 = Sum.pi2 useproof

「かなり」簡単にしていて、filterとかsortとか名ばかりな感じですけれども、これでもダメっていわれるので、Idと依存和の絶妙な辺を読み解いたらこの修行は辞めます。

これやった所で、結局「filterしたリストの長さは、元のリストの長さより短い」としか言えてなくて、多分なんかsortに長さ方向の制約付ければ出来るんじゃないかなぁ。出来ないかなぁ。

多分filterしたリストが、元のリストの出現位置の順序関係を含んだ部分集合であるとか書いても無駄だと思うのでうーん・・・。

この記事 (http://d.hatena.ne.jp/yoshihiro503/20080308) を見ると、Coqのmeasureキーワードさん凄いなーって感じですけど入る前はどうやってたんだろう・・・。

他参考
http://joshkos.blogspot.com/2007/11/qsort-in-agda.html

分かった

lem1 : Id (n + length (filter p xs')) (length xs') -- まずこれが言えるっていう時点で...
lem1 = Sum.pi2 hypo
--lem1' : Id (n + length (filter p xs')) (length xs')
--lem1' = -- id (length xs') -- id (n + length (filter p xs')) -- これらは出来ないらしい。面白い

ここんとこが割と肝で、Sum.pi2 hypoだと良いのにーみたいなのは、結局これが出来るって事はid ?が出来なければ成らないって事を頭の中でさっと考えてlem1'を私が書いちゃったと思うんですけれども、そもそもLEの定義で(λ v -> Id _ _)みたく成ってるので、当然と言えば当然という感じになってるんですね。

もっとも、ここから綺麗に

Id ((succ n) + length (filter p (x :: xs'))) (length (x :: xs'))

を言って、最終的に、リストの大きさの差であるSum.pi2をなんとか言い切ったという所が凄いと思うんですけど言い切る大変さがあってもAgdaさんはなんかそれを上手く利用出来てないので、余りにも悲しいんじゃないでしょうかみたいな・・・。

http://wiki.portal.chalmers.se/agda/pmwiki.php?n=Libraries.AOPA
AOPAのExampleの中に500行近くかけて証明(してるのか分かりませんが)やってるのはあって、まぁ読む気には成りませんし・・・。