Built with Alectryon, running Coq+SerAPI v8.19.0+0.19.3. Bubbles () indicate interactive fragments: hover for details, tap to reveal contents. Use Ctrl+↑Ctrl+↓ to navigate, Ctrl+🖱️ to focus. On Mac, use ⌘ instead of Ctrl.
(** * Theorems about Non-dependent function types *)
[Loading ML file number_string_notation_plugin.cmxs (using legacy method) ... done]
Require Import Types.Forall.LocalOpen Scope path_scope.Local Set Universe Minimization ToSet.Generalizable VariablesA B C D f g n.Definitionarrow@{u u0} (A : Type@{u}) (B : Type@{u0}) := A -> B.#[export] InstanceIsReflexive_arrow : Reflexive arrow :=
fun_ => idmap.#[export] InstanceIsTransitive_arrow : Transitive arrow :=
fun___fg => compose g f.SectionAssumeFunext.Context `{Funext}.(** ** Paths *)(** As for dependent functions, paths [p : f = g] in a function type [A -> B] are equivalent to functions taking values in path types, [H : forall x:A, f x = g x], or concisely [H : f == g]. These are all given in the [Overture], but we can give them separate names for clarity in the non-dependent case. *)Definitionpath_arrow {AB : Type} (fg : A -> B)
: (f == g) -> (f = g)
:= path_forall f g.(** There are a number of combinations of dependent and non-dependent for [apD10_path_forall]; we list all of the combinations as helpful lemmas for rewriting. *)Definitionap10_path_arrow {AB : Type} (fg : A -> B) (h : f == g)
: ap10 (path_arrow f g h) == h
:= apD10_path_forall f g h.DefinitionapD10_path_arrow {AB : Type} (fg : A -> B) (h : f == g)
: apD10 (path_arrow f g h) == h
:= apD10_path_forall f g h.Definitionap10_path_forall {AB : Type} (fg : A -> B) (h : f == g)
: ap10 (path_forall f g h) == h
:= apD10_path_forall f g h.Definitioneta_path_arrow {AB : Type} (fg : A -> B) (p : f = g)
: path_arrow f g (ap10 p) = p
:= eta_path_forall f g p.Definitionpath_arrow_1 {AB : Type} (f : A -> B)
: (path_arrow f f (funx => 1)) = 1
:= eta_path_arrow f f 1.Definitionequiv_ap10 {AB : Type} fg
: (f = g) <~> (f == g)
:= Build_Equiv _ _ (@ap10 A B f g) _.#[export] Instanceisequiv_path_arrow {AB : Type} (fg : A -> B)
: IsEquiv (path_arrow f g) | 0
:= isequiv_path_forall f g.Definitionequiv_path_arrow {AB : Type} (fg : A -> B)
: (f == g) <~> (f = g)
:= equiv_path_forall f g.(** Function extensionality for two-variable functions *)
H: Funext X, Y, Z: Type f, g: X -> Y -> Z
(forall (x : X) (y : Y), f x y = g x y) <~> f = g
H: Funext X, Y, Z: Type f, g: X -> Y -> Z
(forall (x : X) (y : Y), f x y = g x y) <~> f = g
H: Funext X, Y, Z: Type f, g: X -> Y -> Z
(forall (x : X) (y : Y), f x y = g x y) <~> f == g
H: Funext X, Y, Z: Type f, g: X -> Y -> Z x: X
(forally : Y, f x y = g x y) <~> f x = g x
apply equiv_path_arrow.Defined.
H: Funext X, Y, Z: Type f, g: X -> Y -> Z h: forall (x : X) (y : Y), f x y = g x y x: X y: Y
ap100 (equiv_path_arrow2 f g h) x y = h x y
H: Funext X, Y, Z: Type f, g: X -> Y -> Z h: forall (x : X) (y : Y), f x y = g x y x: X y: Y
ap100 (equiv_path_arrow2 f g h) x y = h x y
H: Funext X, Y, Z: Type f, g: X -> Y -> Z h: forall (x : X) (y : Y), f x y = g x y x: X y: Y
ap10 (ap10 (equiv_path_arrow2 f g h) x) y = h x y
H: Funext X, Y, Z: Type f, g: X -> Y -> Z h: forall (x : X) (y : Y), f x y = g x y x: X y: Y
ap10 (equiv_path_arrow2 f g h) x = ?Goal
H: Funext X, Y, Z: Type f, g: X -> Y -> Z h: forall (x : X) (y : Y), f x y = g x y x: X y: Y
ap10 ?Goal y = h x y
H: Funext X, Y, Z: Type f, g: X -> Y -> Z h: forall (x : X) (y : Y), f x y = g x y x: X y: Y
ap10
(equiv_functor_forall_id
(funx : X => equiv_path_arrow (f x) (g x)) h x)
y = h x y
H: Funext X, Y, Z: Type f, g: X -> Y -> Z h: forall (x : X) (y : Y), f x y = g x y x: X y: Y
ap10 (path_forall (f x) (g x) (h x)) y = h x y
apply apD10_path_arrow.Defined.(** ** Path algebra *)Definitionpath_arrow_pp {AB : Type} (fgh : A -> B)
(p : f == g) (q : g == h)
: path_arrow f h (funx => p x @ q x) = path_arrow f g p @ path_arrow g h q
:= path_forall_pp f g h p q.(** ** Transport *)(** Transporting in non-dependent function types is somewhat simpler than in dependent ones. *)
H: Funext A: Type B, C: A -> Type x1, x2: A p: x1 = x2 f: B x1 -> C x1 y: B x2
transport (funx : A => B x -> C x) p f y =
transport C p (f (transport B p^ y))
H: Funext A: Type B, C: A -> Type x1, x2: A p: x1 = x2 f: B x1 -> C x1 y: B x2
transport (funx : A => B x -> C x) p f y =
transport C p (f (transport B p^ y))
destruct p; simpl; auto.Defined.(** This is an improvement to [transport_arrow]. That result only shows that the functions are homotopic, but even without funext, we can prove that these functions are equal. *)
H: Funext A: Type B, C: A -> Type x1, x2: A p: x1 = x2 f: B x1 -> C x1
transport (funx : A => B x -> C x) p f =
transport C p o f o transport B p^
H: Funext A: Type B, C: A -> Type x1, x2: A p: x1 = x2 f: B x1 -> C x1
transport (funx : A => B x -> C x) p f =
transport C p o f o transport B p^
destruct p; auto.Defined.
H: Funext A: Type B: A -> Type C: Type x1, x2: A p: x1 = x2 f: B x1 -> C y: B x2
transport (funx : A => B x -> C) p f y =
f (transport B p^ y)
H: Funext A: Type B: A -> Type C: Type x1, x2: A p: x1 = x2 f: B x1 -> C y: B x2
transport (funx : A => B x -> C) p f y =
f (transport B p^ y)
destruct p; simpl; auto.Defined.(** This is an improvement to [transport_arrow_toconst]. That result shows that the functions are homotopic, but even without funext, we can prove that these functions are equal. *)
H: Funext A: Type B: A -> Type C: Type x1, x2: A p: x1 = x2 f: B x1 -> C
transport (funx : A => B x -> C) p f =
f o transport B p^
H: Funext A: Type B: A -> Type C: Type x1, x2: A p: x1 = x2 f: B x1 -> C
transport (funx : A => B x -> C) p f =
f o transport B p^
destruct p; auto.Defined.
H: Funext A, B: Type C: A -> Type x1, x2: A p: x1 = x2 f: B -> C x1 y: B
transport (funx : A => B -> C x) p f y =
transport C p (f y)
H: Funext A, B: Type C: A -> Type x1, x2: A p: x1 = x2 f: B -> C x1 y: B
transport (funx : A => B -> C x) p f y =
transport C p (f y)
destruct p; simpl; auto.Defined.(** And some naturality and coherence for these laws. *)
H: Funext A: Type B: A -> Type C: Type x1, x2: A p: x1 = x2 f: B x1 -> C y1, y2: B x2 q: y1 = y2
ap (transport (funx : A => B x -> C) p f) q @
transport_arrow_toconst p f y2 =
transport_arrow_toconst p f y1 @
ap (funy : B x2 => f (transport B p^ y)) q
H: Funext A: Type B: A -> Type C: Type x1, x2: A p: x1 = x2 f: B x1 -> C y1, y2: B x2 q: y1 = y2
ap (transport (funx : A => B x -> C) p f) q @
transport_arrow_toconst p f y2 =
transport_arrow_toconst p f y1 @
ap (funy : B x2 => f (transport B p^ y)) q
destruct p, q; reflexivity.Defined.(** ** Dependent paths *)(** Usually, a dependent path over [p:x1=x2] in [P:A->Type] between [y1:P x1] and [y2:P x2] is a path [transport P p y1 = y2] in [P x2]. However, when [P] is a function space, these dependent paths have a more convenient description: rather than transporting the argument of [y1] forwards and backwards, we transport only forwards but on both sides of the equation, yielding a "naturality square". *)
H: Funext A: Type B, C: A -> Type x1, x2: A p: x1 = x2 f: B x1 -> C x1 g: B x2 -> C x2
(forally1 : B x1,
transport C p (f y1) = g (transport B p y1)) <~>
transport (funx : A => B x -> C x) p f = g
H: Funext A: Type B, C: A -> Type x1, x2: A p: x1 = x2 f: B x1 -> C x1 g: B x2 -> C x2
(forally1 : B x1,
transport C p (f y1) = g (transport B p y1)) <~>
transport (funx : A => B x -> C x) p f = g
H: Funext A: Type B, C: A -> Type x1: A f, g: B x1 -> C x1
(forally1 : B x1,
transport C 1 (f y1) = g (transport B 1 y1)) <~>
transport (funx : A => B x -> C x) 1 f = g
apply equiv_path_arrow.Defined.
H: Funext A: Type B, C: A -> Type x1, x2: A p: x1 = x2 f: B x1 -> C x1 g: B x2 -> C x2 h: forally1 : B x1,
transport C p (f y1) = g (transport B p y1) u: B x1
ap10 (dpath_arrow B C p f g h) (transport B p u) =
(transport_arrow p f (transport B p u) @
ap (funx : B x1 => transport C p (f x))
(transport_Vp B p u)) @ h u
H: Funext A: Type B, C: A -> Type x1, x2: A p: x1 = x2 f: B x1 -> C x1 g: B x2 -> C x2 h: forally1 : B x1,
transport C p (f y1) = g (transport B p y1) u: B x1
ap10 (dpath_arrow B C p f g h) (transport B p u) =
(transport_arrow p f (transport B p u) @
ap (funx : B x1 => transport C p (f x))
(transport_Vp B p u)) @ h u
H: Funext A: Type B, C: A -> Type x1: A f, g: B x1 -> C x1 h: forally1 : B x1,
transport C 1 (f y1) = g (transport B 1 y1) u: B x1
apD10
(path_forall (funx : B x1 => f x)
(funx : B x1 => g x) h) u = 1 @ h u
exact (apD10_path_forall f g h u @ (concat_1p _)^).Defined.(** ** Maps on paths *)(** The action of maps given by application. *)Definitionap_apply_l {AB : Type} {xy : A -> B} (p : x = y) (z : A)
: ap (funf => f z) p = ap10 p z
:= 1.Definitionap_apply_Fl {ABC : Type} {xy : A} (p : x = y) (M : A -> B -> C) (z : B)
: ap (funa => (M a) z) p = ap10 (ap M p) z
:= match p with1 => 1end.Definitionap_apply_Fr {ABC : Type} {xy : A} (p : x = y) (z : B -> C) (N : A -> B)
: ap (funa => z (N a)) p = ap01 z (ap N p)
:= (ap_compose N _ _).Definitionap_apply_FlFr {ABC : Type} {xy : A} (p : x = y) (M : A -> B -> C) (N : A -> B)
: ap (funa => (M a) (N a)) p = ap11 (ap M p) (ap N p)
:= match p with1 => 1end.(** The action of maps given by lambda. *)
H: Funext A, B, C: Type x, y: A p: x = y M: A -> B -> C
ap (fun (a : A) (b : B) => M a b) p =
path_arrow (funb : B => (funa : A => M a b) x)
(funb : B => (funa : A => M a b) y)
(funb : B => ap (funa : A => M a b) p)
H: Funext A, B, C: Type x, y: A p: x = y M: A -> B -> C
ap (fun (a : A) (b : B) => M a b) p =
path_arrow (funb : B => (funa : A => M a b) x)
(funb : B => (funa : A => M a b) y)
(funb : B => ap (funa : A => M a b) p)
destruct p;
symmetry;
simpl; apply path_arrow_1.Defined.(** The action of pre/post-composition on a path between functions. See also [ap10_ap_precompose] and [ap10_ap_postcompose] in PathGroupoids.v and [ap_precomposeD] in Forall.v. *)Definitionap_precompose {BPQ : Type}
{fg : Q -> P} (h : f = g) (i : B -> Q)
: ap (fun (k : Q -> P) => k o i) h
= path_arrow (f o i) (g o i) (ap10 h o i)
:= ap_lambdaD _ _.
H: Funext B, P, Q: Type f, g: Q -> P h: f = g j: P -> B
ap (funk : Q -> P => j o k) h =
path_arrow (j o f) (j o g)
(funq : Q => ap j (ap10 h q))
H: Funext B, P, Q: Type f, g: Q -> P h: f = g j: P -> B
ap (funk : Q -> P => j o k) h =
path_arrow (j o f) (j o g)
(funq : Q => ap j (ap10 h q))
symmetry; apply path_forall_1.Defined.(** ** Functorial action *)Definitionfunctor_arrow `(f : B -> A) `(g : C -> D)
: (A -> C) -> (B -> D)
:= @functor_forall A (fun_ => C) B (fun_ => D) f (fun_ => g).Definitionnot_contrapositive `(f : B -> A)
: not A -> not B
:= functor_arrow f idmap.
H: Funext A, B: Type
A <-> B -> ~ A <-> ~ B
H: Funext A, B: Type
A <-> B -> ~ A <-> ~ B
intros e; split; apply not_contrapositive@{_ k}, e.Defined.Definitionap_functor_arrow `(f : B -> A) `(g : C -> D)
(h h' : A -> C) (p : h == h')
: ap (functor_arrow f g) (path_arrow _ _ p)
= path_arrow _ _ (funb => ap g (p (f b)))
:= @ap_functor_forall _ A (fun_ => C) B (fun_ => D)
f (fun_ => g) h h' p.(** ** Truncatedness: functions into an n-type is an n-type *)#[export] Instancecontr_arrow {AB : Type} `{Contr B}
: Contr (A -> B) | 100
:= contr_forall.#[export] Instanceistrunc_arrow {AB : Type} `{IsTrunc n B}
: IsTrunc n (A -> B) | 100
:= istrunc_forall.(** ** Functions from a contractible type *)(** This also follows from [equiv_contr_forall], but this proof has a better inverse map. *)
H: Funext A, B: Type Contr0: Contr A
(A -> B) <~> B
H: Funext A, B: Type Contr0: Contr A
(A -> B) <~> B
H: Funext A, B: Type Contr0: Contr A
(funf : A -> B => f (center A)) o const == idmap
H: Funext A, B: Type Contr0: Contr A
const o (funf : A -> B => f (center A)) == idmap
H: Funext A, B: Type Contr0: Contr A
(funf : A -> B => f (center A)) o const == idmap
reflexivity.
H: Funext A, B: Type Contr0: Contr A
const o (funf : A -> B => f (center A)) == idmap
H: Funext A, B: Type Contr0: Contr A f: A -> B a: A
f (center A) = f a
apply (ap f), contr.Defined.(** ** Equivalences *)#[export] Instanceisequiv_functor_arrow `{IsEquiv B A f} `{IsEquiv C D g}
: IsEquiv (functor_arrow f g) | 1000
:= @isequiv_functor_forall _ A (fun_ => C) B (fun_ => D)
_ _ _ _.Definitionequiv_functor_arrow `{IsEquiv B A f} `{IsEquiv C D g}
: (A -> C) <~> (B -> D)
:= @equiv_functor_forall _ A (fun_ => C) B (fun_ => D)
f _ (fun_ => g) _.Definitionequiv_functor_arrow' `(f : B <~> A) `(g : C <~> D)
: (A -> C) <~> (B -> D)
:= @equiv_functor_forall' _ A (fun_ => C) B (fun_ => D)
f (fun_ => g).(* We could do something like this notation, but it's not clear that it would be that useful, and might be confusing. *)(* Notation "f -> g" := (equiv_functor_arrow' f g) : equiv_scope. *)EndAssumeFunext.(** ** Decidability *)(** This doesn't require funext *)
A, B: Type H: Decidable A H0: Decidable B
Decidable (A -> B)
A, B: Type H: Decidable A H0: Decidable B
Decidable (A -> B)
A, B: Type H: Decidable A H0: Decidable B x2: B
Decidable (A -> B)
A, B: Type H: Decidable A H0: Decidable B y2: ~ B
Decidable (A -> B)
A, B: Type H: Decidable A H0: Decidable B x2: B
Decidable (A -> B)
exact (inl (fun_ => x2)).
A, B: Type H: Decidable A H0: Decidable B y2: ~ B
Decidable (A -> B)
A, B: Type H: Decidable A H0: Decidable B y2: ~ B x1: A
Decidable (A -> B)
A, B: Type H: Decidable A H0: Decidable B y2: ~ B y1: ~ A
Decidable (A -> B)
A, B: Type H: Decidable A H0: Decidable B y2: ~ B x1: A
Decidable (A -> B)
A, B: Type H: Decidable A H0: Decidable B y2: ~ B x1: A f: A -> B
Empty
exact (y2 (f x1)).
A, B: Type H: Decidable A H0: Decidable B y2: ~ B y1: ~ A
Decidable (A -> B)
A, B: Type H: Decidable A H0: Decidable B y2: ~ B y1: ~ A x1: A