はじめてのCubical

Thierry Coquandたちが、univalenceと両立する、dependent type theoryの新しいcomputationalなmodelを作ったと言っている
A model of type theory in cubical sets
http://www.cse.chalmers.se/~coquand/mod1.pdf

これを実装した処理系は
Implementation of Univalence in Cubical Sets
https://github.com/simhu/cubical
に置いてある。適当にcabal installとかすればインストールできる


#新しい処理系なので、若干の仕様変更により、ここに書いたコードは、そのままでは動かなくなっているっぽい。面倒なので修正はしない


細かいことはわたしもよく分かってないけど、今までHoTT(homotopy type theory)というのは、机上の空論だったわけだけど、(Coquandたちが間違ってなければ)これは人類史上初のHoTTの処理系ということになる(このようなモデルは他にもあることは否定されてないので、また挙動の違う別のHoTT処理系が存在しうるかもしれないが)。

#univalenceが成立するということは、functional extensionalityが成立するということで、今まで、そういうtype theoryを作るというのは、色んな人が苦心してきた問題であるので、大きな前進と言える

#quotient typeも作れる

#HoTTから現れたもう一つの新しい概念であるhigher inductive typeについては、現時点では実装されてない


ホモトピー論では、simplicial setというものがよく使われるけど、cubical setというのもあるらしく(今回初めて聞いた)、多分それと関係するのだけど、cubical setの定義は、上の論文にホモトピー論と無関係に与えられている。まぁ、今のところ、これで何でうまくいくのか、理論的なdetailは理解できてない


使用しているtype theoryは
A simple type-theoretic language: Mini-TT
http://www.cse.chalmers.se/~bengt/papers/GKminiTT.pdf
というのを、ほぼそのまま使っているっぽい。これもよく分からないけど、"Mini-TT is a step towards a simple and definitive core language for the proof-assistant Agda based on versions of Martin-Lof Type Theory"とか書いてあるので、何かそういうもんらしい


上のHoTT処理系(便宜的にcubicalと呼んでおく。普通にcabalでinstallすると、cubicalという実行ファイルが得られるので)は実用に使うようなものではなく、あくまで論文の参照実装という位置づけだと思うので、使いやすくはない(CoqやAgdaを実用で使ってるぜって人がいたら、おもちゃみたいなもんだと思う)。マニュアルとかもないけど、syntaxは若干Agdaっぽい(というか、Haskellっぽいと言うべきか)


まず初歩的な例として、こういうの↓を書いて、test.cubとして保存して、cubical test.cubとか打って、File loaded.とか言われれば成功

module test where

-- identity function
id : (A:U) ->A ->A
-- id A x = x
id = \A x -> x

-- S combinator
S : (A B :U) -> A  -> (A->B) -> B
S A B a f = f a

Nat : U
data Nat = zero | succ (n:Nat)

add : Nat -> Nat -> Nat
add = split
  zero -> \y -> y
  succ n -> \y -> succ (add n y)

List : (A:U) -> U
data List A = nil | cons (a:A) (b:List A)

foldr : (A:U) -> (B:U) -> (A -> B -> B) -> B -> List A -> B
foldr A B k z = split
  nil -> z
  cons y ys -> k y (foldr A B k z ys)

このコードにはcubical特有のことは何もないので、何をやってるかは、CoqやAgdaを使ったことあれば分かるはず。Uは多分UniverseのUで、CoqのTypeみたいなもんと思う(SetとかPropはない)。cubicalでファイルを読み込むと、プロンプトが出るので、add zero zeroとかすれば、zeroと評価される



cubicalらしいこととして、
Observational Equality, Now!
http://www.cs.nott.ac.uk/~txa/publ/obseqnow.pdf
の1.1にextensionality lawを手で入れると、canonicityが壊れるよ!という例が書いてあるので、これをやってみる

module ott where

Id   : (A : U) (a b : A) -> U
Id = PN

refl : (A : U) (a : A) -> Id A a a
refl = PN

funExt : (A : U) (B : (a : A) -> U) (f g : (a : A) -> B a)
         (p : ((x : A) -> (Id (B x) (f x) (g x)))) -> Id ((y : A) -> B y) f g
funExt = PN

J : (A : U) (a : A) -> (C : (x : A) -> Id A a x -> U) -> C a (refl A a) ->
      (x : A) -> (p : Id A a x) -> C x p
J = PN


ext : (A B:U) (f g:A->B) (p : (x:A) -> Id B (f x) (g x)) -> Id (A->B) f g
ext A B = funExt A (\_ -> B)

subst : (A : U) (a b : A) (p : Id A a b) (T:A->U) -> T a -> T b
subst A a b p T d = J A a (\ x q -> T x) d b p

Nat : U
data Nat = zero | succ (n:Nat)

add : Nat -> Nat -> Nat
add = split
  zero -> \y -> y
  succ n -> \y -> succ (add n y)

id : (A:U) ->A ->A
id A x = x


add0 : Nat -> Nat
add0 n = add zero n

add0_eq_id : Id (Nat->Nat) add0 (id Nat)
add0_eq_id = ext Nat Nat add0 (id Nat) p
   where
      p : (n:Nat) -> (Id Nat (add0 n) (id Nat n))
      p n = refl Nat n

-- compare with "subst (Nat->Nat) add0 add0 (refl (Nat->Nat) add0) (\_ -> Nat) zero"
test : Nat
test = subst (Nat->Nat) add0 (id Nat) add0_eq_id (\_ -> Nat) zero

PNというのは、処理系に組み込まれてるってことだと思う(多分)。ott.cubを読み込んで、testをevalすると、これはzeroであることが分かる


だから何やねんという感じではあるけど、例えばCoqで同等のコードを

Definition idfun (A:Type) := (fun (x:A)=>x).
Definition add0 := plus 0.
Axiom ext :forall (A B:Type)  (f g:A->B) (p : forall(x:A),f x=g x) , f = g.
Theorem add0_eq_id : add0 = (idfun nat).
Proof.
   apply ext.
   auto.
Defined.

Definition subst (A:Type) (a b:A) (p:a=b) (T:A->Type) : T a -> T b.
   induction p.
   auto.
Defined.

とか定義して、

Eval compute in (subst (nat->nat) add0 (idfun nat) add0_eq_id (fun _=>nat) 0).

を見ても、0にはならない。一方、

Eval compute in (subst (nat->nat) add0 add0 (eq_refl _) (fun _=>nat) 0).

と対比すると、こっちは0になる。直感的には、この2つの式が等しくてもよさそうなものだけど、多分、Coqでは、(subst (nat->nat) add0 (idfun nat) add0_eq_id (fun _=>nat) 0)が0になることは証明できない(当然、0以外の値になることも証明できない)。Coqでも、univalence axiomを手で入れてやって、頑張って証明を書くと、これが0になることが証明できるのだと思う(書けた人は、教えてください)。冒頭で書いた別のモデルがありうるというのは、univalence axiomを仮定しても、こういうclosed termの値が全部決まるかどうか保証はない(Voevodskyは一意に決まると予想している)ということだと思う


あと、quotient typeが作れるってのは実用的に重要かもしれない。今までは、こういうのをSetoidとかで凌いでたんだと思うけど。quotient typeの例は、examples/quotient.cubに、Z/2Zの例が載っている。詳細は見てない