agda 入門@proofsummit 2011
DESCRIPTION
対話的定理証明支援系 Agda の紹介ですTRANSCRIPT
Agda 入門@ikegami _ _
Proof Summit 20112011-09-25
Agda 概要• 依存型関数型言語
• 依存型 = 型が値に依存できる
• 関数型 = 関数が第一級市民
• 対話的定理証明支援系
• tactic なし
コンパイルの話は最後証明開発駆動の人ごめん
Agda で証明• tactic なし
• データを定義 = 公理を与える
• 関数の型を宣言 = 命題を与える
• 関数を定義し、停止させる = 証明する
• Agda が「型検査」に合格と認める
• Agda が「停止する」と認める
キーワード Set
Set型
型の型 Set1
型の型の型 Set2
UniverseUnicode subscriptSet1 とも Set1 とも書ける
データ定義
data Bool : Set where true : Bool false : Bool
TAB は非推奨
データ定義
data Bool : Set where true : Bool false : Bool
空白
TAB は非推奨
データ定義
data Bool : Set where true : Bool false : Bool
TAB は非推奨
データ定義
data Bool : Set where true : Bool false : Bool空白
TAB は非推奨
データ定義
data Bool : Set where true : Bool false : Bool
TAB は非推奨
データ定義
data Bool : Set where true : Bool false : Bool
空白
TAB は非推奨
データ定義
data Bool : Set where true : Bool false : Bool
TAB は非推奨
データ定義
data ℕ : Set where zero : ℕ suc : ℕ → ℕ
データ定義data List (A : Set) : Set where nil : List A cons : (x : A) → (xs : List A) → List A
データ定義data List (A : Set) : Set where nil : List A cons : (x : A) → (xs : List A) → List A
型パラメータ
データ定義data List (A : Set) : Set where nil : List A cons : (x : A) → (xs : List A) → List A
関数定義
pred : ℕ → ℕpred zero = zeropred (suc n) = n
関数は total でなければならない定義域すべてをわたる
Hidden arguments
id : {A : Set} → A → Aid x = x
lambda
id : {A : Set} → A → Aid = λ x → x
Unicode / ASCII
id : {A : Set} → A → Aid = λ x → x
id : {A : Set} -> A -> Aid = \x -> x
UTF8
mixfix オペレータ
_+_ : ℕ → ℕ → ℕzero + n = nsuc m + n = suc (m + n)
mixfix オペレータif_then_else_ : {A : Set} → Bool → A → A → Aif true then t else f = tif false then t else f = f
依存型データdata Vec (A : Set) : ℕ → Setwhere [] : Vec A zero _∷_ : {n : ℕ} → (x : A) → (xs : Vec A n) → Vec A (suc n)
依存型データdata Vec (A : Set) : ℕ → Setwhere [] : Vec A zero _∷_ : {n : ℕ} → (x : A) → (xs : Vec A n) → Vec A (suc n)
型パラメータ
依存型データdata Vec (A : Set) : ℕ → Setwhere [] : Vec A zero _∷_ : {n : ℕ} → (x : A) → (xs : Vec A n) → Vec A (suc n)
レコードrecord R : Set where constructor r field f1 : Bool f2 : ℕ
レコードfoo : Rfoo = record { f1 = true ; f2 = zero }bar : Rbar = r true zero
命題論理とAgda命題論理 Agda
A ならば B
A でない
A または B
A かつ B
Proposition as Set
• A : Set• x が A の proof object
• x : A
A ならば B
• A B : Set• A ならば B
• i : A → B
例 : A ならば A
id : {A : Set} → A → Aid x = x
ユーザが関数定義を証明とみなす
p : {A B C : Set} → (A → B) → (B → C) → A → Cp f g x = ?
p : {A B C : Set} → (A → B) → (B → C) → A → Cp f g x = { }0
?0 : C
p : {A B C : Set} → (A → B) → (B → C) → A → Cp f g x = { g }0
?0 : Cg : B → C
p : {A B C : Set} → (A → B) → (B → C) → A → Cp f g x = { }1
?1 : B
g
p : {A B C : Set} → (A → B) → (B → C) → A → Cp f g x = { f x }1
?1 : Bf : A → B
g
x : A
p : {A B C : Set} → (A → B) → (B → C) → A → Cp f g x = g (f x)
対話的な証明の構築
命題論理とAgda命題論理 Agda
A ならば B A → B
A でない
A または B
A かつ B
空のデータ
data ⊥ : Set where
A でない
• A : Set• A でない• notA : A → ⊥
命題論理とAgda命題論理 Agda
A ならば B A → B
A でない A → ⊥
A または B
A かつ B
disjoint union 型data _⊎_ (A B : Set) : Set where left : A → A ⊎ B right : B → A ⊎ B
命題論理とAgda命題論理 Agda
A ならば B A → B
A でない A → ⊥
A または B A ⊎ B
A かつ B
sigma レコードrecord Σ (A : Set) (B : A → Set) : Set where constructor _,_ field proj1 : A proj2 : B proj1
times 関数
_×_ : (A B : Set) → SetA × B = Σ A (λ x → B)
命題論理とAgda命題論理 Agda
A ならば B A → B
A でない A → ⊥
A または B A ⊎ B
A かつ B A × B
証明できないこと• 二重否定の除去 double negation elimination
• dne : {A : Set} → ¬ (¬ A) → A
• 排中律 Law of the excluded middle
• em :{A : Set} → A ⊎ (¬ A)
• 背理法
• etc.直観主義
停止しない関数foo : ℕ → ℕfoo zero = zerofoo (suc n) = foo (suc n)
型検査は通るしかし、停止するとみなされない
Agda のあれこれ
forall キーワードss : ∀ n → ℕss n = suc (suc n)
ss : (n : ℕ) → ℕss n = suc (suc n)
forall キーワードlength : ∀{n} → {A : Set} → Vec A n → ℕlength {n} {A} v = n
length : {n : ℕ} → {A : Set} → Vec A n → ℕlength {n} {A} v = n
解決されていないHidden argument
foo : ∀{m} → ℕfoo = zero
m が型推論できていない証明としても未完成
解決されていないHidden argument
foo : ∀{m} → ℕfoo = zero
m が型推論できていない証明としても未完成
コメント-- 一行のコメント{-複数行のコメント-}
let と wherefoo : .....foo = let bar : ..... bar = ..... in .....
foo : .....foo = ..... where bar : ..... bar = .....
() パターン
f : {A : Set} → ⊥ → Af ()
data ⊥ : Set where
wildcard パターン
_∧_ : Bool → Bool → Booltrue ∧ b = bfalse ∧ _ = false
with パターンfilter : {A : Set} → (A → Bool) → List A → List Afilter p nil = nilfilter p (cons x xs) with p x... ¦ true = cons x (filter p xs)... ¦ false = filter p xs
dot パターン(の動機)data IsEven : ℕ → Set where evenZ : IsEven zero evenSS : (n : ℕ) →IsEven n → IsEven (suc (suc n))
dot パターン(の動機)data IsEven : ℕ → Set where evenZ : IsEven zero evenSS : (n : ℕ) →IsEven n → IsEven (suc (suc n))even+ : (m n : ℕ) → IsEven m → IsEven n → IsEven (m + n)even+ zero n p q = qeven+ (suc m’) n p q = ?
dot パターン(の動機)data IsEven : ℕ → Set where evenZ : IsEven zero evenSS : (n : ℕ) →IsEven n → IsEven (suc (suc n))
m でパターンマッチすると証明が進まない
even+ : (m n : ℕ) → IsEven m → IsEven n → IsEven (m + n)even+ zero n p q = qeven+ (suc m’) n p q = ?
dot パターン(の動機)data IsEven : ℕ → Set where evenZ : IsEven zero evenSS : (n : ℕ) →IsEven n → IsEven (suc (suc n))even+ : (m n : ℕ) → IsEven m → IsEven n → IsEven (m + n)even+ zero n p q = qeven+ (suc m’) n p q = ?
dot パターンdata IsEven : ℕ → Set where evenZ : IsEven zero evenSS : (n : ℕ) →IsEven n → IsEven (suc (suc n))even+ : (m n : ℕ) → IsEven m → IsEven n → IsEven (m + n)even+ .zero n evenZ q = qeven+ .(suc (suc m’)) n (evenSS m’ p) q = evenSS (m’ + n) (even+ m’ n p q)
dot パターンdata IsEven : ℕ → Set where evenZ : IsEven zero evenSS : (n : ℕ) →IsEven n → IsEven (suc (suc n))even+ : (m n : ℕ) → IsEven m → IsEven n → IsEven (m + n)even+ .zero n evenZ q = qeven+ .(suc (suc m’)) n (evenSS m’ p) q = evenSS (m’ + n) (even+ m’ n p q)
パターンマッチ
dot パターンdata IsEven : ℕ → Set where evenZ : IsEven zero evenSS : (n : ℕ) →IsEven n → IsEven (suc (suc n))even+ : (m n : ℕ) → IsEven m → IsEven n → IsEven (m + n)even+ .zero n evenZ q = qeven+ .(suc (suc m’)) n (evenSS m’ p) q = evenSS (m’ + n) (even+ m’ n p q)
mutual ブロックmutual data Even : Set where zeroE : Even succE : Odd → Even data Odd : Set where succO : Even → Odd
相互に依存するデータ定義
Agda 2.2.12 以降では不要になる
mutual ブロックmutual data Even : Set where zeroE : Even succE : Odd → Even data Odd : Set where succO : Even → Odd
相互に依存するデータ定義
空白
Agda 2.2.12 以降では不要になる
mutual ブロックmutual data Even : Set where zeroE : Even succE : Odd → Even data Odd : Set where succO : Even → Odd
相互に依存するデータ定義
Agda 2.2.12 以降では不要になる
postulate 宣言postulate A : Set foo : A → A
定義なしにシンボルを導入Agda のシステムが壊れる可能性
ご利用は計画的に
postulate 宣言postulate A : Set foo : A → A
定義なしにシンボルを導入Agda のシステムが壊れる可能性
ご利用は計画的に
空白
postulate 宣言postulate A : Set foo : A → A
定義なしにシンボルを導入Agda のシステムが壊れる可能性
ご利用は計画的に
parametrized modulemodule Foo (A : Set) (foo : A → A)where
module Bar wheredata B : Set where b : Bbar : B → Bbar x = x
module F = Foo B Bar
Agda の module についてもうすこし
Ulf のスライド(2006) で 30 枚…
階層的 module
open import Data.Nat
lib/src/Data/Nat.agda
(add-to-list ʻagda2-include-dirs “.../lib/src”)
Agda 標準ライブラリ参照パスの起点が .../lib/src
ファイル名と module
MyProject/Foo.agda
(add-to-list ʻagda2-include-dirs “.../MyProject”)
module Foo wheredata A : Set where a : A
open import 宣言open import Data.Nat
• import 宣言
• Nat.zero と参照できる
• open import 宣言
• zero と参照できるスコープの違い
module using
open import Data.Bool using (Bool; true; false)
module renaming
open import Data.Bool renaming (true to t; false to f)
module hiding
open import Data.Nat hiding (ℕ; zero; suc)
module as
open import Data.Bool as B
foo : B.Boolfoo = B.true
Agda の機能
agda2-goal-and-contextp : {A B C : Set} → (A → B) → (B → C) → A → Cp f g x = { }0
?0 : CCtrl-c Ctrl-,
x : Af : A → Bg : B → C
A B C : Set
agda2-goal-and-context-and-inferred
p : {A B C : Set} → (A → B) → (B → C) → A → Cp f g x = {f x}0
?0 : CCtrl-c Ctrl-.
f x : B
agda2-refinep : {A B C : Set} → (A → B) → (B → C) → A → Cp f g x ={g (f x)}0
Ctrl-c Ctrl-r
g (f x)
agda2-refinep : {A B C : Set} → (A → B) → (B → C) → A → Cp f g x =
Ctrl-c Ctrl-r
g (f x)
ロード/リスタート• Ctrl-C Ctrl-l (agda2-load)
• Ctrl-C Ctrl-x Ctrl-r (agda2-restart)
書いてはやりなおし、書いてはロードする
compile
open import IOopen import Data.Unitmain : IO ⊤main = putStrLn “Hello”
C-c C-x C-c (agda2-compile)
MAlonzo
automation provingp : {A B C : Set} → (A → B) → (B → C) → A → Cp f g x = { }0
Ctrl-c Ctrl-a
これくらいの問題は自動的に解くAgsy
automation provingp : {A B C : Set} → (A → B) → (B → C) → A → Cp f g x =
Ctrl-c Ctrl-a
これくらいの問題は自動的に解くAgsy
automation provingp : {A B C : Set} → (A → B) → (B → C) → A → Cp f g x = g (f x)
Ctrl-c Ctrl-a
これくらいの問題は自動的に解くAgsy
等号についてadvanced topic
equality
data _≡_ {A : Set} (x : A) : A → Setwhere refl : x ≡ x
Leibnitz equality
等号を用いた証明cong : {A B : Set} → (f : A → B) → {x y} → x ≡ y → f x ≡ f ycong f refl = refl
foo : (n : ℕ) -> n + zero ≡ nfoo zero = reflfoo (suc m) =
?0 : suc m ≡ suc m + zero
{ }0
等号を用いた証明cong : {A B : Set} → (f : A → B) → {x y} → x ≡ y → f x ≡ f ycong f refl = refl
foo : (n : ℕ) -> n + zero ≡ nfoo zero = reflfoo (suc m) =
等号を用いた証明cong : {A B : Set} → (f : A → B) → {x y} → x ≡ y → f x ≡ f ycong f refl = refl
foo : (n : ℕ) -> n + zero ≡ nfoo zero = reflfoo (suc m) = cong suc (foo m)
rewrite の動機foo : (n : ℕ) -> n + zero ≡ nfoo zero = reflfoo (suc m) with m + zero ¦ foo m... ¦ .m ¦ refl =
?0 : suc m ≡ suc m
{ }0
rewrite の動機foo : (n : ℕ) -> n + zero ≡ nfoo zero = reflfoo (suc m) with m + zero ¦ foo m... ¦ .m ¦ refl =
rewrite の動機foo : (n : ℕ) -> n + zero ≡ nfoo zero = reflfoo (suc m) with m + zero ¦ foo m... ¦ .m ¦ refl = refl
rewritefoo : (n : ℕ) → n + zero ≡ nfoo zero = reflfoo (suc m) rewrite plus-zero m =
?0 : suc m ≡ suc m
{ }0
rewritefoo : (n : ℕ) → n + zero ≡ nfoo zero = reflfoo (suc m) rewrite plus-zero m =
rewritefoo : (n : ℕ) → n + zero ≡ nfoo zero = reflfoo (suc m) rewrite plus-zero m = refl
rewrite
f : .....f ps rewrite eqn = rhs
eqn : a ≡ b
f : .....f ps with a ¦ eqn... ¦ ._ ¦ refl = rhs
equality reasoningopen import Data.Listopen import Data.List.Propertiesopen import Relation.Binary.PropositionalEquality as Pr : {A : Set} → (xs : List A) → reverse (reverse xs) ≡ xsr nil = reflr (cons x xs) = begin reverse (reverse (cons x xs)) ≡⟨ ?0 ⟩
reverse (reverse xs ++ cons x nil) ..... cons x xs ∎ where open P.≡-reasoning
equality reasoning
r : {A : Set} → (xs : List A) → reverse (reverse xs) ≡ xsr nil = reflr (cons x xs) = begin reverse (reverse (cons x xs)) ≡⟨ ?0 ⟩
reverse (reverse xs ++ cons x nil) ..... cons x xs ∎ where open P.≡-reasoning
?0 : reverse (reverse (cons x xs)) ≡ reverse (reverse xs ++ cons x nil)
equality reasoning
r : {A : Set} → (xs : List A) → reverse (reverse xs) ≡ xsr nil = reflr (cons x xs) = begin reverse (reverse (cons x xs)) ≡⟨ cong reverse (unfold-reverse x xs) ⟩
reverse (reverse xs ++ cons x nil) ..... cons x xs ∎ where open P.≡-reasoning
?0 : reverse (reverse (cons x xs)) ≡ reverse (reverse xs ++ cons x nil)
標準ライブラリにある関数の型を調べて
入力することが tactic に相当
emptiness check
f : (n : ℕ) → n ≡ suc n → ℕf n ()
Agda 2.2.12 Feature
プラグマとフラグ
--universe-polymorphism
Set型 型の型
Set1型の型の型Set2
{-# OPTIONS --universe-polymorphism #-}module Foo wheref : ∀{a} → Set a → .....f = .....
Agda 標準ライブラリに頻出
Universe
Agda 2.2.12 以降ではデフォルトで有効になる
agda コマンド• --compile
• コンパイル MAlonzo
• --html
• HTML ドキュメント生成
• フラグ無し
• 型検査
• etc. (たくさんのオプション)
Agda release notes
• Agda 2-2-0 (2009-03-18)
• Sized type
sized typessub : ℕ → ℕ → ℕsub zero n = zerosub (suc m) zero = suc msub (suc m) (suc n) = sub m n-- div m n computes ceiling (m/(n+1))div : ℕ → ℕ → ℕdiv zero n = zerodiv (suc m) n = suc (div (sub m n) n)
停止しない
sized typessub : ℕ → ℕ → ℕsub zero n = zerosub (suc m) zero = suc msub (suc m) (suc n) = sub m n-- div m n computes ceiling (m/(n+1))div : ℕ → ℕ → ℕdiv zero n = zerodiv (suc m) n = suc (div (sub m n) n)
停止しない
{-# OPTIONS --sized-types #-}open import Size
data Nat : {i : Size} → Set where zero : {i : Size} → Nat {↑ i} suc : {i : Size} → Nat {i} → Nat {↑ i}
sub : {i : Size} → Nat {i} → Nat {∞} → Nat {i}sub zero n = zerosub (suc m) zero = suc msub (suc m) (suc n) = sub m n-- div m n computes ceiling (m/(n+1))div : {i j : Size} → Nat {i} → Nat {j} → Nat {i}div zero n = zerodiv (suc m) n = suc (div (sub m n) n)
型宣言を Sized Type にするだけで停止する
Agda release notes
• Agda 2.2.10 (2011-02-21)
• --without-K flag
• irrelevant declarations
• termination checker with projections
• compiler backend
• Epic
• MAlonzo
Epic コンパイラ• Epic 言語とコンパイラ
• http://www.cs.st-andrews.ac.uk/~eb/epic.php
• Agda から Epic への言語変換
• Epic コンパイラは C を経由
MAlonzo コンパイラ
• Agda で型安全、停止
• Haskell で型検査しなくてもいいね(!?)
• unsafeCoerce :: a -> b
Agda の構文木をそのまま Haskell の構文木にする
他言語 (experimental)
• JavaScript Compiler Backend
• Ruby Compiler Backend
• https://github.com/larrytheliquid/agda-rb
Agda release notes
• Agda 2.2.12 (current development)
• coming soon (maybe within this week?)
• instance arguments {{ }}
• pattern matching lambda
Agda in browser
• Agda + JavaScript Compiler
• Functional Reactive Programming
• Example : Clock
あとでデモ
時間確認
DemoKeyCastr.app 起動Emacs.app 起動 (Command + T でフォント変更)
[1B_Maze-Black 25pt font]ディスプレイをミラーするようモニタ変更
まだ理解してないこと• Agda standard library の一部
• well-founded induction
• coinduction
• --without-K フラグ
• irrelevant declaration
• projection and termination
• instance arguments
• pattern matching lambda
• reflection
• etc. (too much)