証明の大まかな流れは、x1で反例があるとすると、それより小さいx2も反例になって、無限降下法より反例が無い事が言える、です。
2014-07-15
18/11/18 完成しました!
19/08/31 完成してねえええ!
20/09/19 完成したかな
証明の大まかな流れは、x1で反例があるとすると、それより小さいx2も反例になって、無限降下法より反例が無い事が言える、です。
2014-07-15
18/11/18 完成しました!
19/08/31 完成してねえええ!
20/09/19 完成したかな
本記事では、関数型言語に触れているよくでてくる モナド について書きます。
Stateモナドを数学的に実装する
Idrisでやってみた。
Control.Monad.Stateにもある。そこではモナド変換子として実装されている。
module MyState %default total -- %language ElabReflection -- %hide return -- Stateモナド record State (stateType : Type) (a : Type) where constructor ST runState : stateType -> (a, stateType) implementation Functor (State stateType) where map f (ST g) = ?rhs1 implementation Applicative (State stateType) where pure x = ST $ \s => (x, s) (ST f) <*> (ST a) = ?rhs2 implementation Monad (State stateType) where m >>= k = ST $ \s => let (x, s0) = runState m s in runState (k x) s0 -- プレリュードでやってる -- return : Monad m => a -> m a -- return = pure get : State x x get = ST $ \s => (s, s) put : s -> State s () put s = ST $ const ((), s) -- ------------------------- -- アキュムレータ -- xを取り、stateに加え、更新したstateを出力 accumulator : Int -> State Int Int accumulator x = do state <- get let y = state + x put y return y -- 実行 -- bind(>>=)は左から右へ進む -- > runState ((accumulator 3) >>= accumulator) 4 -- (14, 14) : (Int, Int) -- アキュムレータ2 accumulator2 : List Int -> State Int (List Int) accumulator2 [] = return [] accumulator2 (x::_) = do state <- get let y = state + x put y return [y] partial -- ↓どこが全域でないか分からないが…… multiple : State Int (List Int) multiple = do (a::_) <- accumulator2 [1] -- [2]が返る (b::_) <- accumulator2 [1] -- [3]が返る、参照透過じゃない!(と、見せかけている) (c::_) <- accumulator2 [2] (d::_) <- accumulator2 [3] (e::_) <- accumulator2 [0] (f::_) <- accumulator2 [-1] return [a, b, c, d, e, f] -- 実行 -- runStateの中でだけ、状態が保持される -- > runState multiple 1 -- ([2, 3, 5, 8, 8, 7], 7) : (List Int, Int)
元記事のメイン内容だけど、随伴からStateモナドが作られるのですね。
知らなかった。
自分もそこまでやるかは分からない。
rev_rev_idとは、リストに、逆順にする事を2回すると、元に戻る、というやつだ。
みょんみょんさんがIsabelleで、
いとうかつとしさんがAgdaで、実装動画を上げている。
ならば僕は、Idrisでやろう、と奮い立った。
(Idrisを起動するときは、> idris -XElabReflectionってやったら良い事があるかもしれない)
出来た物はこちら。
module rev_rev_id %default total a : List Nat a = [1, 2, 3, 4] snoc : List Nat -> Nat -> List Nat snoc [] y = [y] snoc (x::xs) y = x :: snoc xs y myReverse : List Nat -> List Nat myReverse [] = [] myReverse (x::xs) = snoc (myReverse xs) x lemma : (xs:List Nat) -> (y:Nat) -> myReverse (snoc xs y) = y :: (myReverse xs) lemma [] _ = Refl lemma (x::xs) y = rewrite lemma xs y in Refl theorem : (xs:List Nat) -> myReverse (myReverse xs) = xs theorem [] = Refl theorem (x::xs) = rewrite lemma (myReverse xs) x in rewrite theorem xs in Refl
お二人と、ほぼ同じ形になった。
これでも苦労したのですよ、簡約されすぎたりして。
あと話は変わるけれど、Idrisのコマンドプロンプトはカラフルでかっこいい。
181020 追記 Reasoningを使った証明もやってみた。
libs/base/Syntax/PreorderReasoning.idr にライブラリがある。
module rev_rev_id02 -- > idris -p base import Syntax.PreorderReasoning %default total -- %language ElabReflection snoc : List a -> a -> List a snoc [] y = [y] snoc (x::xs) y = x :: snoc xs y myReverse : List a -> List a myReverse [] = [] myReverse (x::xs) = snoc (myReverse xs) x lemma : (xs:List a) -> (y:a) -> myReverse (snoc xs y) = y :: (myReverse xs) lemma [] _ = Refl lemma (x::xs) y = rewrite lemma xs y in Refl theorem : (xs:List a) -> myReverse (myReverse xs) = xs theorem [] = Refl theorem (x :: xs) = (myReverse (myReverse (x::xs))) ={ Refl }= (myReverse (snoc (myReverse xs) x)) ={ lemma (myReverse xs) x }= (x :: (myReverse (myReverse xs))) ={ cong {f=(x::)} (theorem xs) }= (x :: xs) QED
整数の定義を素朴なものに戻した。
--(succ (succ (pred zero))などが有効、という弱点がある) data Z : Set where zero : Z succ : Z -> Z pred : Z -> Z
それに加法、反数、乗法を定義したものがこちら。
整数の素朴な定義
この整数が環をなすことをAgdaで証明した。
証明にはrewriteばかり使っている。-Reasoningは使わなかった。
あれ使いづらいもん。
整数が環をなす
ガチな定義も考えたけどね
--(succ (succ (pred zero))などはもうできない) mutual data Z : Set where zero : Z succ : (x : Z) -> isTrue (zeroOrSucc x) -> Z pred : (x : Z) -> isTrue (zeroOrPred x) -> Z zeroOrSucc : Z -> Bool zeroOrSucc zero = true zeroOrSucc (succ x p) = true zeroOrSucc (pred x p) = false zeroOrPred : Z -> Bool zeroOrPred zero = true zeroOrPred (succ x p) = false zeroOrPred (pred x p) = true -- succ (succ zero tt) tt のように使う
諸事情により、本シリーズを終了します。
@suharahiromichi
「The Little Prover」のCoqでの実現
この文書のソースコードは以下にあります。
https://github.com/suharahiromichi/coq/blob/master/lisp/tlp_lisp_3.v
以下のコードを実行するときは、氏のCoqコードを読み込んだ後にお願いします。
リスト型帰納法による証明をおこなう。
(** Chapter6 最後まで考え抜くのです *) (* 書き換え用に公理を付け足す *) Variable xs : star. Variable membE : memb (CONS (CAR xs) (remb (CDR xs))) = (_IF (ATOM (CONS (CAR xs) (remb (CDR xs)))) 'NIL (_IF (EQUAL (CAR (CONS (CAR xs) (remb (CDR xs)))) '?) 'T (memb (CDR (CONS (CAR xs) (remb (CDR xs))))))). Variable rembE : remb xs = (_IF (ATOM xs) '() (_IF (EQUAL (CAR xs) '?) (remb (CDR xs)) (CONS (CAR xs) (remb (CDR xs))))). Variable EQA : (EQUAL 'NIL 'NIL) = 'T. Theorem memb_remb : ~ ATOM xs -> ATOM xs -> ~ (EQUAL (CAR xs) '?) -> (EQUAL (CAR xs) '?) -> (EQUAL (memb (remb (CDR xs))) 'NIL) -> (_IF (ATOM xs) (EQUAL (memb (remb xs)) 'NIL) (_IF (EQUAL (memb (remb (CDR xs))) 'NIL) (EQUAL (memb (remb xs)) 'NIL) 'T)). Proof. move => H0 H1 H2 H3 H4. rewrite rembE. rewrite {1}(iffLR ifAP (if_nest_A (ATOM xs) '() (_IF (EQUAL (CAR xs) '?) (remb (CDR xs)) (CONS (CAR xs) (remb (CDR xs)))) )). rewrite membB. rewrite atomB. rewrite (equal_eq (if_true 'NIL (_IF (EQUAL (CAR '()) '?) 'T (memb (CDR '()))))). rewrite EQA. (* rewrite rembE. *) rewrite (iffLR ifEP (if_nest_E (ATOM xs) '() (_IF (EQUAL (CAR xs) '?) (remb (CDR xs)) (CONS (CAR xs) (remb (CDR xs)))) )). (* --- ifの持ち上げ --- *) rewrite -(equal_eq (if_same (EQUAL (CAR xs) '?) (memb (_IF (EQUAL (CAR xs) '?) (remb (CDR xs)) (CONS (CAR xs) (remb (CDR xs))))) )). rewrite {1}(iffLR ifAP (if_nest_A (EQUAL (CAR xs) '?) (remb (CDR xs)) (CONS (CAR xs) (remb (CDR xs))) )). rewrite (iffLR ifEP (if_nest_E (EQUAL (CAR xs) '?) (remb (CDR xs)) (CONS (CAR xs) (remb (CDR xs))) )). (* --- ifの持ち上げ --- *) rewrite {2}(iffLR ifAP (equal_if (memb (remb (CDR xs))) 'NIL)). rewrite membE. rewrite (equal_eq (atom_cons (CAR xs) (remb (CDR xs)))). rewrite (equal_eq (if_false 'NIL (_IF (EQUAL (CAR (CONS (CAR xs) (remb (CDR xs)))) '?) 'T (memb (CDR (CONS (CAR xs) (remb (CDR xs)))))))). rewrite (equal_eq (car_cons (CAR xs) (remb (CDR xs )))). rewrite (equal_eq (cdr_cons (CAR xs) (remb (CDR xs )))). rewrite (iffLR ifEP (if_nest_E (EQUAL (CAR xs) '?) 'T (memb (remb (CDR xs))) )). rewrite {2}(iffLR ifAP (equal_if (memb (remb (CDR xs))) 'NIL)). rewrite (equal_eq (if_same (EQUAL (CAR xs) '?) 'NIL)). rewrite EQA. rewrite (equal_eq (if_same (EQUAL (memb (remb (CDR xs))) 'NIL) 'T)). rewrite (equal_eq (if_same (ATOM xs) 'T)). done. done. done. done. done. done. done. done. Qed.
番外編ということで、定理証明手習いをAgdaでやってみた。
最初は、組み込み関数を普通に定義して、公理をpostulateで定義した。
そしたら問題が発生。
以下を考える。
data Star : Set where NIL : Star TRU : Star N : Nat → Star S : String → Star C : Star → Star → Star ATOM : Star → Star ATOM (C _ _) = NIL ATOM _ = TRU
ATOMを使った証明にxs:Starを引数とすると、
xsをコンストラクタでばらせないから、ATOMが計算できず、エラーになる。
引数にC x yとか渡さないといけない。これはやりたくない。
長いSchemeの定理を何度も書かないといけない。
congの位置合わせも手間だった。
というわけで全部postulateにした。
証明もrewriteを使うようにした。
これなら書けるかもしれない。
rewriteで証明ステップが5つくらい一気に進んだのは謎。
ソースはこちらです。
TLP01.agdaボツネタ
TLP02.agda