The idea is to match the precedence used in regular programming languages, where `x = y || x = z` is parsed as `(x = y) || (x = z)`. This commit also adds `!x` as notation for `bnot x`
584 lines
18 KiB
Text
584 lines
18 KiB
Text
/-
|
||
Copyright (c) 2014 Microsoft Corporation. All rights reserved.
|
||
Released under Apache 2.0 license as described in the file LICENSE.
|
||
Authors: Leonardo de Moura
|
||
|
||
notation, basic datatypes and type classes
|
||
-/
|
||
prelude
|
||
|
||
notation `Prop` := Sort 0
|
||
notation f ` $ `:1 a:0 := f a
|
||
|
||
/- Logical operations and relations -/
|
||
|
||
reserve prefix `¬`:40
|
||
reserve prefix `~`:40
|
||
reserve infixr ` ∧ `:35
|
||
reserve infixr ` /\ `:35
|
||
reserve infixr ` \/ `:30
|
||
reserve infixr ` ∨ `:30
|
||
reserve infix ` <-> `:20
|
||
reserve infix ` ↔ `:20
|
||
reserve infix ` = `:50
|
||
reserve infix ` == `:50
|
||
reserve infix ` ≠ `:50
|
||
reserve infix ` ≈ `:50
|
||
reserve infix ` ~ `:50
|
||
reserve infix ` ≡ `:50
|
||
reserve infixl ` ⬝ `:75
|
||
reserve infixr ` ▸ `:75
|
||
reserve infixr ` ▹ `:75
|
||
|
||
/- types and type constructors -/
|
||
|
||
reserve infixr ` ⊕ `:30
|
||
reserve infixr ` × `:35
|
||
|
||
/- arithmetic operations -/
|
||
|
||
reserve infixl ` + `:65
|
||
reserve infixl ` - `:65
|
||
reserve infixl ` * `:70
|
||
reserve infixl ` / `:70
|
||
reserve infixl ` % `:70
|
||
reserve prefix `-`:100
|
||
reserve infixr ` ^ `:80
|
||
|
||
reserve infixr ` ∘ `:90 -- input with \comp
|
||
|
||
reserve infix ` <= `:50
|
||
reserve infix ` ≤ `:50
|
||
reserve infix ` < `:50
|
||
reserve infix ` >= `:50
|
||
reserve infix ` ≥ `:50
|
||
reserve infix ` > `:50
|
||
|
||
/- boolean operations -/
|
||
|
||
reserve prefix `!`:40
|
||
reserve infixl ` && `:35
|
||
reserve infixl ` || `:30
|
||
|
||
/- set operations -/
|
||
|
||
reserve infix ` ∈ `:50
|
||
reserve infix ` ∉ `:50
|
||
reserve infixl ` ∩ `:70
|
||
reserve infixl ` ∪ `:65
|
||
reserve infix ` ⊆ `:50
|
||
reserve infix ` ⊇ `:50
|
||
reserve infix ` ⊂ `:50
|
||
reserve infix ` ⊃ `:50
|
||
reserve infix ` \ `:70
|
||
|
||
/- other symbols -/
|
||
|
||
reserve infix ` ∣ `:50
|
||
reserve infixl ` ++ `:65
|
||
reserve infixr ` :: `:67
|
||
reserve infixl `; `:1
|
||
|
||
universes u v w
|
||
|
||
/-
|
||
The kernel definitional equality test (t =?= s) has special support for id_delta applications.
|
||
It implements the following rules
|
||
|
||
1) (id_delta t) =?= t
|
||
2) t =?= (id_delta t)
|
||
3) (id_delta t) =?= s IF (unfold_of t) =?= s
|
||
4) t =?= id_delta s IF t =?= (unfold_of s)
|
||
|
||
This is mechanism for controlling the delta reduction (aka unfolding) used in the kernel.
|
||
|
||
We use id_delta applications to address performance problems when type checking
|
||
lemmas generated by the equation compiler.
|
||
-/
|
||
@[inline] def id_delta {α : Sort u} (a : α) : α :=
|
||
a
|
||
|
||
/-- Gadget for optional parameter support. -/
|
||
@[reducible] def opt_param (α : Sort u) (default : α) : Sort u :=
|
||
α
|
||
|
||
/-- Gadget for marking output parameters in type classes. -/
|
||
@[reducible] def out_param (α : Sort u) : Sort u := α
|
||
|
||
/-- Auxiliary declaration used to implement the notation (a : α) -/
|
||
@[reducible] def typed_expr (α : Sort u) (a : α) : α := a
|
||
|
||
/-
|
||
id_rhs is an auxiliary declaration used in the equation compiler to address performance
|
||
issues when proving equational lemmas. The equation compiler uses it as a marker.
|
||
-/
|
||
abbreviation id_rhs (α : Sort u) (a : α) : α := a
|
||
|
||
inductive punit : Sort u
|
||
| star : punit
|
||
|
||
/-- An abbreviation for `punit.{0}`, its most common instantiation.
|
||
This type should be preferred over `punit` where possible to avoid
|
||
unnecessary universe parameters. -/
|
||
abbreviation unit : Type := punit
|
||
|
||
@[pattern] abbreviation unit.star : unit := punit.star
|
||
|
||
/--
|
||
Gadget for defining thunks, thunk parameters have special treatment.
|
||
Example: given
|
||
def f (s : string) (t : thunk nat) : nat
|
||
an application
|
||
f "hello" 10
|
||
is converted into
|
||
f "hello" (λ _, 10)
|
||
-/
|
||
@[reducible] def thunk (α : Type u) : Type u :=
|
||
unit → α
|
||
|
||
inductive true : Prop
|
||
| intro : true
|
||
|
||
inductive false : Prop
|
||
|
||
inductive empty : Type
|
||
|
||
def not (a : Prop) : Prop := a → false
|
||
prefix `¬` := not
|
||
|
||
inductive eq {α : Sort u} (a : α) : α → Prop
|
||
| refl : eq a
|
||
|
||
/-
|
||
Initialize the quotient module, which effectively adds the following definitions:
|
||
|
||
constant quot {α : Sort u} (r : α → α → Prop) : Sort u
|
||
|
||
constant quot.mk {α : Sort u} (r : α → α → Prop) (a : α) : quot r
|
||
|
||
constant quot.lift {α : Sort u} {r : α → α → Prop} {β : Sort v} (f : α → β) :
|
||
(∀ a b : α, r a b → eq (f a) (f b)) → quot r → β
|
||
|
||
constant quot.ind {α : Sort u} {r : α → α → Prop} {β : quot r → Prop} :
|
||
(∀ a : α, β (quot.mk r a)) → ∀ q : quot r, β q
|
||
-/
|
||
init_quotient
|
||
|
||
inductive heq {α : Sort u} (a : α) : Π {β : Sort u}, β → Prop
|
||
| refl : heq a
|
||
|
||
structure prod (α : Type u) (β : Type v) :=
|
||
(fst : α) (snd : β)
|
||
|
||
/-- Similar to `prod`, but α and β can be propositions.
|
||
We use this type internally to automatically generate the brec_on recursor. -/
|
||
structure pprod (α : Sort u) (β : Sort v) :=
|
||
(fst : α) (snd : β)
|
||
|
||
structure and (a b : Prop) : Prop :=
|
||
intro :: (left : a) (right : b)
|
||
|
||
def and.elim_left {a b : Prop} (h : and a b) : a := h.1
|
||
|
||
def and.elim_right {a b : Prop} (h : and a b) : b := h.2
|
||
|
||
/- eq basic support -/
|
||
|
||
infix = := eq
|
||
|
||
attribute [refl] eq.refl
|
||
|
||
@[pattern] def rfl {α : Sort u} {a : α} : a = a := eq.refl a
|
||
|
||
@[elab_as_eliminator, subst]
|
||
lemma eq.subst {α : Sort u} {P : α → Prop} {a b : α} (h₁ : a = b) (h₂ : P a) : P b :=
|
||
eq.rec h₂ h₁
|
||
|
||
notation h1 ▸ h2 := eq.subst h1 h2
|
||
|
||
@[trans] lemma eq.trans {α : Sort u} {a b c : α} (h₁ : a = b) (h₂ : b = c) : a = c :=
|
||
h₂ ▸ h₁
|
||
|
||
@[symm] lemma eq.symm {α : Sort u} {a b : α} (h : a = b) : b = a :=
|
||
h ▸ rfl
|
||
|
||
infix == := heq
|
||
|
||
@[pattern] def heq.rfl {α : Sort u} {a : α} : a == a := heq.refl a
|
||
|
||
lemma eq_of_heq {α : Sort u} {a a' : α} (h : a == a') : a = a' :=
|
||
have ∀ (α' : Sort u) (a' : α') (h₁ : @heq α a α' a') (h₂ : α = α'), (eq.rec_on h₂ a : α') = a', from
|
||
λ (α' : Sort u) (a' : α') (h₁ : @heq α a α' a'), heq.rec_on h₁ (λ h₂ : α = α, rfl),
|
||
show (eq.rec_on (eq.refl α) a : α) = a', from
|
||
this α a' h (eq.refl α)
|
||
|
||
/- The following four lemmas could not be automatically generated when the
|
||
structures were declared, so we prove them manually here. -/
|
||
lemma prod.mk.inj {α : Type u} {β : Type v} {x₁ : α} {y₁ : β} {x₂ : α} {y₂ : β}
|
||
: (x₁, y₁) = (x₂, y₂) → and (x₁ = x₂) (y₁ = y₂) :=
|
||
λ h, prod.no_confusion h (λ h₁ h₂, ⟨h₁, h₂⟩)
|
||
|
||
lemma prod.mk.inj_arrow {α : Type u} {β : Type v} {x₁ : α} {y₁ : β} {x₂ : α} {y₂ : β}
|
||
: (x₁, y₁) = (x₂, y₂) → Π ⦃P : Sort w⦄, (x₁ = x₂ → y₁ = y₂ → P) → P :=
|
||
λ h₁ _ h₂, prod.no_confusion h₁ h₂
|
||
|
||
lemma pprod.mk.inj {α : Sort u} {β : Sort v} {x₁ : α} {y₁ : β} {x₂ : α} {y₂ : β}
|
||
: pprod.mk x₁ y₁ = pprod.mk x₂ y₂ → and (x₁ = x₂) (y₁ = y₂) :=
|
||
λ h, pprod.no_confusion h (λ h₁ h₂, ⟨h₁, h₂⟩)
|
||
|
||
lemma pprod.mk.inj_arrow {α : Type u} {β : Type v} {x₁ : α} {y₁ : β} {x₂ : α} {y₂ : β}
|
||
: (x₁, y₁) = (x₂, y₂) → Π ⦃P : Sort w⦄, (x₁ = x₂ → y₁ = y₂ → P) → P :=
|
||
λ h₁ _ h₂, prod.no_confusion h₁ h₂
|
||
|
||
inductive sum (α : Type u) (β : Type v)
|
||
| inl {} (val : α) : sum
|
||
| inr {} (val : β) : sum
|
||
|
||
inductive psum (α : Sort u) (β : Sort v)
|
||
| inl {} (val : α) : psum
|
||
| inr {} (val : β) : psum
|
||
|
||
inductive or (a b : Prop) : Prop
|
||
| inl {} (h : a) : or
|
||
| inr {} (h : b) : or
|
||
|
||
def or.intro_left {a : Prop} (b : Prop) (ha : a) : or a b :=
|
||
or.inl ha
|
||
|
||
def or.intro_right (a : Prop) {b : Prop} (hb : b) : or a b :=
|
||
or.inr hb
|
||
|
||
structure sigma {α : Type u} (β : α → Type v) :=
|
||
mk :: (fst : α) (snd : β fst)
|
||
|
||
structure psigma {α : Sort u} (β : α → Sort v) :=
|
||
mk :: (fst : α) (snd : β fst)
|
||
|
||
inductive bool : Type
|
||
| ff : bool
|
||
| tt : bool
|
||
|
||
/- Remark: subtype must take a Sort instead of Type because of the axiom strong_indefinite_description. -/
|
||
structure subtype {α : Sort u} (p : α → Prop) :=
|
||
(val : α) (property : p val)
|
||
|
||
attribute [pp_using_anonymous_constructor] sigma psigma subtype pprod and
|
||
|
||
class inductive decidable (p : Prop)
|
||
| is_false (h : ¬p) : decidable
|
||
| is_true (h : p) : decidable
|
||
|
||
@[reducible]
|
||
def decidable_pred {α : Sort u} (r : α → Prop) :=
|
||
Π (a : α), decidable (r a)
|
||
|
||
@[reducible]
|
||
def decidable_rel {α : Sort u} (r : α → α → Prop) :=
|
||
Π (a b : α), decidable (r a b)
|
||
|
||
@[reducible]
|
||
def decidable_eq (α : Sort u) :=
|
||
decidable_rel (@eq α)
|
||
|
||
inductive option (α : Type u)
|
||
| none {} : option
|
||
| some (val : α) : option
|
||
|
||
export option (none some)
|
||
export bool (ff tt)
|
||
|
||
inductive list (T : Type u)
|
||
| nil {} : list
|
||
| cons (hd : T) (tl : list) : list
|
||
|
||
notation h :: t := list.cons h t
|
||
notation `[` l:(foldr `, ` (h t, list.cons h t) list.nil `]`) := l
|
||
|
||
inductive nat
|
||
| zero : nat
|
||
| succ (n : nat) : nat
|
||
|
||
/- Declare builtin and reserved notation -/
|
||
|
||
class has_zero (α : Type u) := (zero : α)
|
||
class has_one (α : Type u) := (one : α)
|
||
class has_add (α : Type u) := (add : α → α → α)
|
||
class has_mul (α : Type u) := (mul : α → α → α)
|
||
class has_inv (α : Type u) := (inv : α → α)
|
||
class has_neg (α : Type u) := (neg : α → α)
|
||
class has_sub (α : Type u) := (sub : α → α → α)
|
||
class has_div (α : Type u) := (div : α → α → α)
|
||
class has_dvd (α : Type u) := (dvd : α → α → Prop)
|
||
class has_mod (α : Type u) := (mod : α → α → α)
|
||
class has_le (α : Type u) := (le : α → α → Prop)
|
||
class has_lt (α : Type u) := (lt : α → α → Prop)
|
||
class has_append (α : Type u) := (append : α → α → α)
|
||
class has_andthen (α : Type u) (β : Type v) (σ : out_param $ Type w) := (andthen : α → β → σ)
|
||
class has_union (α : Type u) := (union : α → α → α)
|
||
class has_inter (α : Type u) := (inter : α → α → α)
|
||
class has_sdiff (α : Type u) := (sdiff : α → α → α)
|
||
class has_equiv (α : Sort u) := (equiv : α → α → Prop)
|
||
class has_subset (α : Type u) := (subset : α → α → Prop)
|
||
class has_ssubset (α : Type u) := (ssubset : α → α → Prop)
|
||
/- Type classes has_emptyc and has_insert are
|
||
used to implement polymorphic notation for collections.
|
||
Example: {a, b, c}. -/
|
||
class has_emptyc (α : Type u) := (emptyc : α)
|
||
class has_insert (α : out_param $ Type u) (γ : Type v) := (insert : α → γ → γ)
|
||
/- Type class used to implement the notation { a ∈ c | p a } -/
|
||
class has_sep (α : out_param $ Type u) (γ : Type v) :=
|
||
(sep : (α → Prop) → γ → γ)
|
||
/- Type class for set-like membership -/
|
||
class has_mem (α : out_param $ Type u) (γ : Type v) := (mem : α → γ → Prop)
|
||
|
||
class has_pow (α : Type u) (β : Type v) :=
|
||
(pow : α → β → α)
|
||
|
||
export has_andthen (andthen)
|
||
export has_pow (pow)
|
||
|
||
infix ∈ := has_mem.mem
|
||
notation a ∉ s := ¬ has_mem.mem a s
|
||
infix + := has_add.add
|
||
infix * := has_mul.mul
|
||
infix - := has_sub.sub
|
||
infix / := has_div.div
|
||
infix ∣ := has_dvd.dvd
|
||
infix % := has_mod.mod
|
||
prefix - := has_neg.neg
|
||
infix <= := has_le.le
|
||
infix ≤ := has_le.le
|
||
infix < := has_lt.lt
|
||
infix ++ := has_append.append
|
||
infix ; := andthen
|
||
notation `∅` := has_emptyc.emptyc _
|
||
infix ∪ := has_union.union
|
||
infix ∩ := has_inter.inter
|
||
infix ⊆ := has_subset.subset
|
||
infix ⊂ := has_ssubset.ssubset
|
||
infix \ := has_sdiff.sdiff
|
||
infix ≈ := has_equiv.equiv
|
||
infixr ^ := has_pow.pow
|
||
|
||
export has_append (append)
|
||
|
||
@[reducible] def ge {α : Type u} [has_le α] (a b : α) : Prop := has_le.le b a
|
||
@[reducible] def gt {α : Type u} [has_lt α] (a b : α) : Prop := has_lt.lt b a
|
||
|
||
infix >= := ge
|
||
infix ≥ := ge
|
||
infix > := gt
|
||
|
||
@[reducible] def superset {α : Type u} [has_subset α] (a b : α) : Prop := has_subset.subset b a
|
||
@[reducible] def ssuperset {α : Type u} [has_ssubset α] (a b : α) : Prop := has_ssubset.ssubset b a
|
||
|
||
infix ⊇ := superset
|
||
infix ⊃ := ssuperset
|
||
|
||
def bit0 {α : Type u} [s : has_add α] (a : α) : α := a + a
|
||
def bit1 {α : Type u} [s₁ : has_one α] [s₂ : has_add α] (a : α) : α := (bit0 a) + 1
|
||
|
||
attribute [pattern] has_zero.zero has_one.one bit0 bit1 has_add.add has_neg.neg
|
||
|
||
def insert {α : Type u} {γ : Type v} [has_insert α γ] : α → γ → γ :=
|
||
has_insert.insert
|
||
|
||
/- The empty collection -/
|
||
def singleton {α : Type u} {γ : Type v} [has_emptyc γ] [has_insert α γ] (a : α) : γ :=
|
||
has_insert.insert a ∅
|
||
|
||
/- nat basic instances -/
|
||
|
||
namespace nat
|
||
protected def add : nat → nat → nat
|
||
| a zero := a
|
||
| a (succ b) := succ (add a b)
|
||
|
||
/- We mark the following definitions as pattern to make sure they can be used in recursive equations,
|
||
and reduced by the equation compiler. -/
|
||
attribute [pattern] nat.add nat.add._main
|
||
end nat
|
||
|
||
instance : has_zero nat := ⟨nat.zero⟩
|
||
|
||
instance : has_one nat := ⟨nat.succ (nat.zero)⟩
|
||
|
||
instance : has_add nat := ⟨nat.add⟩
|
||
|
||
def std.priority.default : nat := 1000
|
||
def std.priority.max : nat := 0xFFFFFFFF
|
||
|
||
namespace nat
|
||
protected def prio := std.priority.default + 100
|
||
end nat
|
||
|
||
/-
|
||
Global declarations of right binding strength
|
||
|
||
If a module reassigns these, it will be incompatible with other modules that adhere to these
|
||
conventions.
|
||
|
||
When hovering over a symbol, use "C-c C-k" to see how to input it.
|
||
-/
|
||
def std.prec.max : nat := 1024 -- the strength of application, identifiers, (, [, etc.
|
||
def std.prec.arrow : nat := 25
|
||
|
||
/-
|
||
The next def is "max + 10". It can be used e.g. for postfix operations that should
|
||
be stronger than application.
|
||
-/
|
||
|
||
def std.prec.max_plus : nat := std.prec.max + 10
|
||
|
||
reserve postfix `⁻¹`:std.prec.max_plus -- input with \sy or \-1 or \inv
|
||
postfix ⁻¹ := has_inv.inv
|
||
|
||
notation α × β := prod α β
|
||
-- notation for n-ary tuples
|
||
|
||
/- sizeof -/
|
||
|
||
class has_sizeof (α : Sort u) :=
|
||
(sizeof : α → nat)
|
||
|
||
def sizeof {α : Sort u} [s : has_sizeof α] : α → nat :=
|
||
has_sizeof.sizeof
|
||
|
||
/-
|
||
Declare sizeof instances and lemmas for types declared before has_sizeof.
|
||
From now on, the inductive compiler will automatically generate sizeof instances and lemmas.
|
||
-/
|
||
|
||
/- Every type `α` has a default has_sizeof instance that just returns 0 for every element of `α` -/
|
||
protected def default.sizeof (α : Sort u) : α → nat
|
||
| a := 0
|
||
|
||
instance default_has_sizeof (α : Sort u) : has_sizeof α :=
|
||
⟨default.sizeof α⟩
|
||
|
||
protected def nat.sizeof : nat → nat
|
||
| n := n
|
||
|
||
instance : has_sizeof nat :=
|
||
⟨nat.sizeof⟩
|
||
|
||
protected def prod.sizeof {α : Type u} {β : Type v} [has_sizeof α] [has_sizeof β] : (prod α β) → nat
|
||
| ⟨a, b⟩ := 1 + sizeof a + sizeof b
|
||
|
||
instance (α : Type u) (β : Type v) [has_sizeof α] [has_sizeof β] : has_sizeof (prod α β) :=
|
||
⟨prod.sizeof⟩
|
||
|
||
protected def sum.sizeof {α : Type u} {β : Type v} [has_sizeof α] [has_sizeof β] : (sum α β) → nat
|
||
| (sum.inl a) := 1 + sizeof a
|
||
| (sum.inr b) := 1 + sizeof b
|
||
|
||
instance (α : Type u) (β : Type v) [has_sizeof α] [has_sizeof β] : has_sizeof (sum α β) :=
|
||
⟨sum.sizeof⟩
|
||
|
||
protected def psum.sizeof {α : Type u} {β : Type v} [has_sizeof α] [has_sizeof β] : (psum α β) → nat
|
||
| (psum.inl a) := 1 + sizeof a
|
||
| (psum.inr b) := 1 + sizeof b
|
||
|
||
instance (α : Type u) (β : Type v) [has_sizeof α] [has_sizeof β] : has_sizeof (psum α β) :=
|
||
⟨psum.sizeof⟩
|
||
|
||
protected def sigma.sizeof {α : Type u} {β : α → Type v} [has_sizeof α] [∀ a, has_sizeof (β a)] : sigma β → nat
|
||
| ⟨a, b⟩ := 1 + sizeof a + sizeof b
|
||
|
||
instance (α : Type u) (β : α → Type v) [has_sizeof α] [∀ a, has_sizeof (β a)] : has_sizeof (sigma β) :=
|
||
⟨sigma.sizeof⟩
|
||
|
||
protected def psigma.sizeof {α : Type u} {β : α → Type v} [has_sizeof α] [∀ a, has_sizeof (β a)] : psigma β → nat
|
||
| ⟨a, b⟩ := 1 + sizeof a + sizeof b
|
||
|
||
instance (α : Type u) (β : α → Type v) [has_sizeof α] [∀ a, has_sizeof (β a)] : has_sizeof (psigma β) :=
|
||
⟨psigma.sizeof⟩
|
||
|
||
protected def punit.sizeof : punit → nat
|
||
| u := 1
|
||
|
||
instance : has_sizeof punit := ⟨punit.sizeof⟩
|
||
|
||
protected def bool.sizeof : bool → nat
|
||
| b := 1
|
||
|
||
instance : has_sizeof bool := ⟨bool.sizeof⟩
|
||
|
||
protected def option.sizeof {α : Type u} [has_sizeof α] : option α → nat
|
||
| none := 1
|
||
| (some a) := 1 + sizeof a
|
||
|
||
instance (α : Type u) [has_sizeof α] : has_sizeof (option α) :=
|
||
⟨option.sizeof⟩
|
||
|
||
protected def list.sizeof {α : Type u} [has_sizeof α] : list α → nat
|
||
| list.nil := 1
|
||
| (list.cons a l) := 1 + sizeof a + list.sizeof l
|
||
|
||
instance (α : Type u) [has_sizeof α] : has_sizeof (list α) :=
|
||
⟨list.sizeof⟩
|
||
|
||
protected def subtype.sizeof {α : Type u} [has_sizeof α] {p : α → Prop} : subtype p → nat
|
||
| ⟨a, _⟩ := sizeof a
|
||
|
||
instance {α : Type u} [has_sizeof α] (p : α → Prop) : has_sizeof (subtype p) :=
|
||
⟨subtype.sizeof⟩
|
||
|
||
lemma nat_add_zero (n : nat) : n + 0 = n := rfl
|
||
|
||
/- Combinator calculus -/
|
||
namespace combinator
|
||
universes u₁ u₂ u₃
|
||
def I {α : Type u₁} (a : α) := a
|
||
def K {α : Type u₁} {β : Type u₂} (a : α) (b : β) := a
|
||
def S {α : Type u₁} {β : Type u₂} {γ : Type u₃} (x : α → β → γ) (y : α → β) (z : α) := x z (y z)
|
||
end combinator
|
||
|
||
/-- Auxiliary datatype for #[ ... ] notation.
|
||
#[1, 2, 3, 4] is notation for
|
||
|
||
bin_tree.node
|
||
(bin_tree.node (bin_tree.leaf 1) (bin_tree.leaf 2))
|
||
(bin_tree.node (bin_tree.leaf 3) (bin_tree.leaf 4))
|
||
|
||
We use this notation to input long sequences without exhausting the system stack space.
|
||
Later, we define a coercion from `bin_tree` into `list`.
|
||
-/
|
||
inductive bin_tree (α : Type u)
|
||
| empty {} : bin_tree
|
||
| leaf (val : α) : bin_tree
|
||
| node (left right : bin_tree) : bin_tree
|
||
|
||
attribute [elab_simple] bin_tree.node bin_tree.leaf
|
||
|
||
/-- Like `by apply_instance`, but not dependent on the tactic framework. -/
|
||
@[reducible] def infer_instance {α : Type u} [i : α] : α := i
|
||
|
||
/- Boolean operators -/
|
||
|
||
@[inline] def cond {a : Type u} : bool → a → a → a
|
||
| tt x y := x
|
||
| ff x y := y
|
||
|
||
@[inline] def bor : bool → bool → bool
|
||
| tt _ := tt
|
||
| ff tt := tt
|
||
| ff ff := ff
|
||
|
||
@[inline] def band : bool → bool → bool
|
||
| ff _ := ff
|
||
| tt ff := ff
|
||
| tt tt := tt
|
||
|
||
@[inline] def bnot : bool → bool
|
||
| tt := ff
|
||
| ff := tt
|
||
|
||
@[inline] def bxor : bool → bool → bool
|
||
| tt ff := tt
|
||
| ff tt := tt
|
||
| _ _ := ff
|
||
|
||
notation !x := bnot x
|
||
notation x || y := bor x y
|
||
notation x && y := band x y
|