LaPToP Blueprint

8. Theory Design and Implementation🔗

Definition8.1
Group: Hehner's Chapter 7: "the stack, the queue, and the tree ... are presented here as case studies in theory design and implementation", a theory being "a contract between two parties, an implementer and a user". The data theories of Section 7.0 are formalized in LaPToP.TheoryDesign.Stack , SimpleStack , Queue and Tree ; program-stack theory (Section 7.1) in LaPToP.TheoryDesign.ProgramStack . (8)
Group member previews
Preview
Theorem 8.2
Loading preview
Group member preview content is loaded from the rendered-fragment cache.
Statement uses 3
Statement dependency previews
Preview
Definition 2.1
Loading preview
Statement dependency preview content is loaded from the rendered-fragment cache.
Used by 4
Reverse dependency previews
Preview
Theorem 8.2
Loading preview
Reverse dependency preview content is loaded from the rendered-fragment cache.
L∃∀N

"We introduce the syntax \mathit{stack}, \mathit{empty}, \mathit{push}, \mathit{pop}, and \mathit{top}." The axioms: \mathit{empty} : \mathit{stack}, \mathit{push} : \mathit{stack} \to X \to \mathit{stack}, \mathit{pop} : \mathit{stack} \to \mathit{stack}, \mathit{top} : \mathit{stack} \to X; construction \mathit{empty}, \mathit{push}\ \mathit{stack}\ X : \mathit{stack} (equivalently P\,\mathit{empty} \land (\forall s : \mathit{stack} \cdot \forall x : X \cdot P\,s \Rightarrow P(\mathit{push}\ s\ x)) \Leftarrow \forall s : \mathit{stack} \cdot P\,s); induction \mathit{empty}, \mathit{push}\ B\ X : B \Rightarrow \mathit{stack} : B (equivalently P\,\mathit{empty} \land (\forall s : \mathit{stack} \cdot \forall x : X \cdot P\,s \Rightarrow P(\mathit{push}\ s\ x)) \Rightarrow \forall s : \mathit{stack} \cdot P\,s), "to exclude anything else from being a stack"; "to say that the constructors always construct different stacks", \mathit{push}\ s\ x \neq \mathit{empty} and \mathit{push}\ s\ x = \mathit{push}\ t\ y = (s = t \land x = y); and "last in, first out": \mathit{pop}(\mathit{push}\ s\ x) = s, \mathit{top}(\mathit{push}\ s\ x) = x. A theory is a Lean structure DataStackTheory X — a carrier type (the bunch \mathit{stack}, taken as a type so that the operations are total on it), the four operations, and the axioms as fields; construction is automatic for a type, and both predicate forms are proved. Consequences: every stack is \mathit{empty} or a \mathit{push}, and the LIFO axioms alone make \mathit{push} injective. "According to the axioms we have so far" — before the last four — "it is possible that all stacks are equal": the one-element carrier satisfies the weak axioms, so \mathit{push}\ s\ x \neq \mathit{empty} is independent of them. Uses Definition 2.1, Definition 3.1 and Theorem 7.2.

Lean code for Definition8.110 declarations
  • structure(10 fields)defined in LaPToP/TheoryDesign/Stack.lean
    complete
    structure LaPToP.TheoryDesign.DataStackTheory.{u, v} (X : Type u) :
      Type (max u (v + 1))
    structure LaPToP.TheoryDesign.DataStackTheory.{u, v}
      (X : Type u) : Type (max u (v + 1))
    A *data-stack theory* over items `X` (aPToP §7.0.0): the syntax `stack`,
    `empty`, `push`, `pop`, `top` together with the data-stack axioms. 
    Stack : Type v
    `stack`, "a bunch consisting of all stacks of items of type `X`". 
    empty : self.Stack
    `empty: stack`, "a stack containing no items". 
    push : self.Stack  X  self.Stack
    `push: stack→X→stack`, "the stack containing the same items plus the one new item". 
    pop : self.Stack  self.Stack
    `pop: stack→stack`, "the stack minus the newest remaining item". 
    top : self.Stack  X
    `top: stack→X`, "the newest remaining item". 
    induction :  (P : self.Stack  Prop),
      P self.empty  (∀ (s : self.Stack) (x : X), P s  P (self.push s x))   (s : self.Stack), P s
    Induction: `P empty ∧ (∀s: stack· ∀x: X· P s ⇒ P (push s x)) ⇒ ∀s: stack· P s`
    — "to exclude anything else from being a stack". 
    push_ne_empty :  (s : self.Stack) (x : X), self.push s x  self.empty
    `push s x ⧧ empty`: "the constructors always construct different stacks". 
    push_inj :  (s t : self.Stack) (x y : X), self.push s x = self.push t y  s = t  x = y
    `push s x = push t y = s=t ∧ x=y`. 
    pop_push :  (s : self.Stack) (x : X), self.pop (self.push s x) = s
    `pop (push s x) = s` ("last in, first out"). 
    top_push :  (s : self.Stack) (x : X), self.top (self.push s x) = x
    `top (push s x) = x` ("last in, first out"). 
  • complete
    theorem LaPToP.TheoryDesign.DataStackTheory.construction.{u, u_1} {X : Type u}
      (T : LaPToP.TheoryDesign.DataStackTheory X) (s : T.Stack) (x : X) :
      T.push s x  Set.univ
    theorem LaPToP.TheoryDesign.DataStackTheory.construction.{u,
        u_1}
      {X : Type u}
      (T :
        LaPToP.TheoryDesign.DataStackTheory X)
      (s : T.Stack) (x : X) :
      T.push s x  Set.univ
    The construction axiom `empty, push stack X: stack`: automatic, since the
    carrier is a type. 
  • complete
    theorem LaPToP.TheoryDesign.DataStackTheory.construction_pred.{u, u_1}
      {X : Type u} (T : LaPToP.TheoryDesign.DataStackTheory X)
      (P : T.Stack  Prop) (h :  (s : T.Stack), P s) :
      P T.empty   (s : T.Stack) (x : X), P s  P (T.push s x)
    theorem LaPToP.TheoryDesign.DataStackTheory.construction_pred.{u,
        u_1}
      {X : Type u}
      (T :
        LaPToP.TheoryDesign.DataStackTheory X)
      (P : T.Stack  Prop)
      (h :  (s : T.Stack), P s) :
      P T.empty 
         (s : T.Stack) (x : X),
          P s  P (T.push s x)
    The predicate form of construction:
    `P empty ∧ (∀s: stack· ∀x: X· P s ⇒ P (push s x)) ⇐ ∀s: stack· P s`. 
  • complete
    theorem LaPToP.TheoryDesign.DataStackTheory.induction_bunch.{u, u_1}
      {X : Type u} (T : LaPToP.TheoryDesign.DataStackTheory X)
      (B : LaPToP.BasicTheories.Bunch T.Stack) (h0 : T.empty  B)
      (hs :  s  B,  (x : X), T.push s x  B) : Set.univ  B
    theorem LaPToP.TheoryDesign.DataStackTheory.induction_bunch.{u,
        u_1}
      {X : Type u}
      (T :
        LaPToP.TheoryDesign.DataStackTheory X)
      (B : LaPToP.BasicTheories.Bunch T.Stack)
      (h0 : T.empty  B)
      (hs :
         s  B,  (x : X), T.push s x  B) :
      Set.univ  B
    The bunch form of induction: `empty, push B X: B ⇒ stack: B`. 
  • complete
    theorem LaPToP.TheoryDesign.DataStackTheory.eq_empty_or_push.{u, u_1}
      {X : Type u} (T : LaPToP.TheoryDesign.DataStackTheory X)
      (s : T.Stack) : s = T.empty   t x, s = T.push t x
    theorem LaPToP.TheoryDesign.DataStackTheory.eq_empty_or_push.{u,
        u_1}
      {X : Type u}
      (T :
        LaPToP.TheoryDesign.DataStackTheory X)
      (s : T.Stack) :
      s = T.empty   t x, s = T.push t x
    Every stack is `empty` or a `push`. 
  • complete
    theorem LaPToP.TheoryDesign.DataStackTheory.push_inj_of_lifo.{u, u_1}
      {X : Type u} (T : LaPToP.TheoryDesign.DataStackTheory X)
      (s t : T.Stack) (x y : X) (h : T.push s x = T.push t y) :
      s = t  x = y
    theorem LaPToP.TheoryDesign.DataStackTheory.push_inj_of_lifo.{u,
        u_1}
      {X : Type u}
      (T :
        LaPToP.TheoryDesign.DataStackTheory X)
      (s t : T.Stack) (x y : X)
      (h : T.push s x = T.push t y) :
      s = t  x = y
    `push` is injective in both arguments — a consequence of the LIFO axioms
    alone (`pop` and `top` recover the arguments), so the second "different
    stacks" axiom is derivable from them. 
  • structure(6 fields)defined in LaPToP/TheoryDesign/Stack.lean
    complete
    structure LaPToP.TheoryDesign.WeakStackTheory.{u, v} (X : Type u) :
      Type (max u (v + 1))
    structure LaPToP.TheoryDesign.WeakStackTheory.{u, v}
      (X : Type u) : Type (max u (v + 1))
    The first six axioms of data-stack theory: typing, construction (automatic)
    and induction. 
    Stack : Type v
    The carrier. 
    empty : self.Stack
    `empty`. 
    push : self.Stack  X  self.Stack
    `push`. 
    pop : self.Stack  self.Stack
    `pop`. 
    top : self.Stack  X
    `top`. 
    induction :  (P : self.Stack  Prop),
      P self.empty  (∀ (s : self.Stack) (x : X), P s  P (self.push s x))   (s : self.Stack), P s
    Induction. 
  • complete
    def LaPToP.TheoryDesign.DataStackTheory.toWeak.{u, u_1} {X : Type u}
      (T : LaPToP.TheoryDesign.DataStackTheory X) :
      LaPToP.TheoryDesign.WeakStackTheory X
    def LaPToP.TheoryDesign.DataStackTheory.toWeak.{u,
        u_1}
      {X : Type u}
      (T :
        LaPToP.TheoryDesign.DataStackTheory
          X) :
      LaPToP.TheoryDesign.WeakStackTheory X
    Every data-stack theory is in particular a weak one. 
  • complete
    def LaPToP.TheoryDesign.unitStack.{u} (X : Type u) [Inhabited X] :
      LaPToP.TheoryDesign.WeakStackTheory X
    def LaPToP.TheoryDesign.unitStack.{u}
      (X : Type u) [Inhabited X] :
      LaPToP.TheoryDesign.WeakStackTheory X
    The one-element model of the weak axioms, in which all stacks are equal. 
  • complete
    theorem LaPToP.TheoryDesign.unitStack_push_eq_empty.{u} (X : Type u)
      [Inhabited X] (s : (LaPToP.TheoryDesign.unitStack X).Stack) (x : X) :
      (LaPToP.TheoryDesign.unitStack X).push s x =
        (LaPToP.TheoryDesign.unitStack X).empty
    theorem LaPToP.TheoryDesign.unitStack_push_eq_empty.{u}
      (X : Type u) [Inhabited X]
      (s :
        (LaPToP.TheoryDesign.unitStack
            X).Stack)
      (x : X) :
      (LaPToP.TheoryDesign.unitStack X).push s
          x =
        (LaPToP.TheoryDesign.unitStack
            X).empty
    In the one-element model `push s x = empty`: the "different stacks" axiom
    `push s x ⧧ empty` is not a consequence of the weak axioms. 
Theorem8.2
Group: Hehner's Chapter 7: "the stack, the queue, and the tree ... are presented here as case studies in theory design and implementation", a theory being "a contract between two parties, an implementer and a user". The data theories of Section 7.0 are formalized in LaPToP.TheoryDesign.Stack , SimpleStack , Queue and Tree ; program-stack theory (Section 7.1) in LaPToP.TheoryDesign.ProgramStack . (8)
Group member previews
Preview
Definition 8.1
Loading preview
Group member preview content is loaded from the rendered-fragment cache.
Statement uses 3
Statement dependency previews
Preview
Definition 4.9
Loading preview
Statement dependency preview content is loaded from the rendered-fragment cache.
Used by 2
Reverse dependency previews
Preview
Theorem 8.3
Loading preview
Reverse dependency preview content is loaded from the rendered-fragment cache.
L∃∀N

"Suppose that lists and functions are implemented. Then we can implement a stack of integers by the following definitions: \mathit{stack} = [*\mathit{int}], \mathit{empty} = [\mathit{nil}], \mathit{push} = \langle s : \mathit{stack} \cdot \langle x : \mathit{int} \cdot s ;; [x] \rangle\rangle, \mathit{pop} = \langle s : \mathit{stack} \cdot \mathbf{if}\ s = \mathit{empty}\ \mathbf{then}\ \mathit{empty}\ \mathbf{else}\ s\,[0;..\# s - 1] \rangle, \mathit{top} = \langle s : \mathit{stack} \cdot \mathbf{if}\ s = \mathit{empty}\ \mathbf{then}\ 0\ \mathbf{else}\ s\,(\# s - 1) \rangle. To prove that a theory is implemented, we prove (the axioms of the theory) \Leftarrow (the definitions of the implementation). ... According to a distributive law, this can be done one axiom at a time." The book's worked calculation is \mathit{top}(\mathit{push}\ s\ x) = x; here every axiom is proved and the implementation is a term of type DataStackTheory ℤ — the induction axiom by induction on lists from the right. "Since we implemented it using list and function theory, we know that if list and function theory are consistent, so is stack theory." Uses Definition 8.1, Definition 4.9 and Theorem 4.10.

Lean code for Theorem8.211 declarations
  • complete
    def LaPToP.TheoryDesign.ListStack.empty : LaPToP.DataStructures.HList 
    def LaPToP.TheoryDesign.ListStack.empty :
      LaPToP.DataStructures.HList 
    `empty = [nil]`. 
  • complete
    def LaPToP.TheoryDesign.ListStack.push (s : LaPToP.DataStructures.HList )
      (x : ) : LaPToP.DataStructures.HList 
    def LaPToP.TheoryDesign.ListStack.push
      (s : LaPToP.DataStructures.HList )
      (x : ) : LaPToP.DataStructures.HList 
    `push s x = s;;[x]`. 
  • complete
    def LaPToP.TheoryDesign.ListStack.pop (s : LaPToP.DataStructures.HList ) :
      LaPToP.DataStructures.HList 
    def LaPToP.TheoryDesign.ListStack.pop
      (s : LaPToP.DataStructures.HList ) :
      LaPToP.DataStructures.HList 
    `pop s = if s=empty then empty else s [0;..#s–1]`. 
  • complete
    def LaPToP.TheoryDesign.ListStack.top (s : LaPToP.DataStructures.HList ) :
      
    def LaPToP.TheoryDesign.ListStack.top
      (s : LaPToP.DataStructures.HList ) : 
    `top s = if s=empty then 0 else s (#s–1)`. 
  • complete
    theorem LaPToP.TheoryDesign.ListStack.push_contents
      (s : LaPToP.DataStructures.HList ) (x : ) :
      (LaPToP.TheoryDesign.ListStack.push s x).contents = s.contents ++ [x]
    theorem LaPToP.TheoryDesign.ListStack.push_contents
      (s : LaPToP.DataStructures.HList )
      (x : ) :
      (LaPToP.TheoryDesign.ListStack.push s
            x).contents =
        s.contents ++ [x]
    `push s x = ⟨s.contents ++ [x]⟩`. 
  • complete
    theorem LaPToP.TheoryDesign.ListStack.push_ne_empty
      (s : LaPToP.DataStructures.HList ) (x : ) :
      LaPToP.TheoryDesign.ListStack.push s x 
        LaPToP.TheoryDesign.ListStack.empty
    theorem LaPToP.TheoryDesign.ListStack.push_ne_empty
      (s : LaPToP.DataStructures.HList )
      (x : ) :
      LaPToP.TheoryDesign.ListStack.push s x 
        LaPToP.TheoryDesign.ListStack.empty
    `push s x ⧧ empty`. 
  • complete
    theorem LaPToP.TheoryDesign.ListStack.induction
      (P : LaPToP.DataStructures.HList   Prop)
      (h0 : P LaPToP.TheoryDesign.ListStack.empty)
      (hs :
         (s : LaPToP.DataStructures.HList ) (x : ),
          P s  P (LaPToP.TheoryDesign.ListStack.push s x))
      (s : LaPToP.DataStructures.HList ) : P s
    theorem LaPToP.TheoryDesign.ListStack.induction
      (P :
        LaPToP.DataStructures.HList   Prop)
      (h0 :
        P LaPToP.TheoryDesign.ListStack.empty)
      (hs :
         (s : LaPToP.DataStructures.HList )
          (x : ),
          P s 
            P
              (LaPToP.TheoryDesign.ListStack.push
                s x))
      (s : LaPToP.DataStructures.HList ) :
      P s
    Induction for lists viewed as stacks: from the right. 
  • complete
    theorem LaPToP.TheoryDesign.ListStack.pop_push
      (s : LaPToP.DataStructures.HList ) (x : ) :
      LaPToP.TheoryDesign.ListStack.pop
          (LaPToP.TheoryDesign.ListStack.push s x) =
        s
    theorem LaPToP.TheoryDesign.ListStack.pop_push
      (s : LaPToP.DataStructures.HList )
      (x : ) :
      LaPToP.TheoryDesign.ListStack.pop
          (LaPToP.TheoryDesign.ListStack.push
            s x) =
        s
    `pop (push s x) = s`: "index the list". 
  • complete
    theorem LaPToP.TheoryDesign.ListStack.top_push
      (s : LaPToP.DataStructures.HList ) (x : ) :
      LaPToP.TheoryDesign.ListStack.top
          (LaPToP.TheoryDesign.ListStack.push s x) =
        x
    theorem LaPToP.TheoryDesign.ListStack.top_push
      (s : LaPToP.DataStructures.HList )
      (x : ) :
      LaPToP.TheoryDesign.ListStack.top
          (LaPToP.TheoryDesign.ListStack.push
            s x) =
        x
    `top (push s x) = x`, the book's worked calculation. 
  • complete
    theorem LaPToP.TheoryDesign.ListStack.push_inj
      (s t : LaPToP.DataStructures.HList ) (x y : ) :
      LaPToP.TheoryDesign.ListStack.push s x =
          LaPToP.TheoryDesign.ListStack.push t y 
        s = t  x = y
    theorem LaPToP.TheoryDesign.ListStack.push_inj
      (s t : LaPToP.DataStructures.HList )
      (x y : ) :
      LaPToP.TheoryDesign.ListStack.push s x =
          LaPToP.TheoryDesign.ListStack.push t
            y 
        s = t  x = y
    `push s x = push t y = s=t ∧ x=y`. 
  • complete
    def LaPToP.TheoryDesign.ListStack.theory :
      LaPToP.TheoryDesign.DataStackTheory 
    def LaPToP.TheoryDesign.ListStack.theory :
      LaPToP.TheoryDesign.DataStackTheory 
    "The definitions must satisfy the axioms": lists implement data-stack theory. 
Theorem8.3
Group: Hehner's Chapter 7: "the stack, the queue, and the tree ... are presented here as case studies in theory design and implementation", a theory being "a contract between two parties, an implementer and a user". The data theories of Section 7.0 are formalized in LaPToP.TheoryDesign.Stack , SimpleStack , Queue and Tree ; program-stack theory (Section 7.1) in LaPToP.TheoryDesign.ProgramStack . (8)
Group member previews
Preview
Definition 8.1
Loading preview
Group member preview content is loaded from the rendered-fragment cache.
uses 1used by 0L∃∀N

"Is stack theory complete? To show that a binary expression is unclassified, we must implement stacks twice, making the expression a theorem in one implementation, and an antitheorem in the other. The expressions \mathit{pop}\ \mathit{empty} = \mathit{empty} and \mathit{top}\ \mathit{empty} = 0 are theorems in our implementation, but we can alter the implementation as follows — \mathit{pop} = \langle s \cdot \mathbf{if}\ s = \mathit{empty}\ \mathbf{then}\ \mathit{push}\ \mathit{empty}\ 0\ \mathbf{else}\ \ldots \rangle, \mathit{top} = \langle s \cdot \mathbf{if}\ s = \mathit{empty}\ \mathbf{then}\ 1\ \mathbf{else}\ \ldots \rangle — to make them antitheorems. So stack theory is incomplete." Both implementations are terms of type DataStackTheory ℤ, and neither \mathit{pop}\ \mathit{empty} = \mathit{empty} nor its negation holds in every model. "The stack user must not use \mathit{pop}\ \mathit{empty} = \mathit{empty} even though the stack implementer has provided it; if the user wants it, it should be added to the theory." Uses Theorem 8.2.

Lean code for Theorem8.39 declarations
  • complete
    theorem LaPToP.TheoryDesign.ListStack.pop_empty :
      LaPToP.TheoryDesign.ListStack.pop
          LaPToP.TheoryDesign.ListStack.empty =
        LaPToP.TheoryDesign.ListStack.empty
    theorem LaPToP.TheoryDesign.ListStack.pop_empty :
      LaPToP.TheoryDesign.ListStack.pop
          LaPToP.TheoryDesign.ListStack.empty =
        LaPToP.TheoryDesign.ListStack.empty
    `pop empty = empty` is a theorem of this implementation ... 
  • complete
    theorem LaPToP.TheoryDesign.ListStack.top_empty :
      LaPToP.TheoryDesign.ListStack.top
          LaPToP.TheoryDesign.ListStack.empty =
        0
    theorem LaPToP.TheoryDesign.ListStack.top_empty :
      LaPToP.TheoryDesign.ListStack.top
          LaPToP.TheoryDesign.ListStack.empty =
        0
    ... and so is `top empty = 0`. 
  • complete
    def LaPToP.TheoryDesign.ListStack'.pop (s : LaPToP.DataStructures.HList ) :
      LaPToP.DataStructures.HList 
    def LaPToP.TheoryDesign.ListStack'.pop
      (s : LaPToP.DataStructures.HList ) :
      LaPToP.DataStructures.HList 
    The alternative `pop = ⟨s: stack· if s=empty then push empty 0 else s [0;..#s–1]⟩`. 
  • complete
    def LaPToP.TheoryDesign.ListStack'.top (s : LaPToP.DataStructures.HList ) :
      
    def LaPToP.TheoryDesign.ListStack'.top
      (s : LaPToP.DataStructures.HList ) : 
    The alternative `top = ⟨s: stack· if s=empty then 1 else s (#s–1)⟩`. 
  • complete
    def LaPToP.TheoryDesign.ListStack'.theory :
      LaPToP.TheoryDesign.DataStackTheory 
    def LaPToP.TheoryDesign.ListStack'.theory :
      LaPToP.TheoryDesign.DataStackTheory 
    The alternative implementation also satisfies the axioms. 
  • complete
    theorem LaPToP.TheoryDesign.ListStack'.pop_empty_ne :
      LaPToP.TheoryDesign.ListStack'.pop
          LaPToP.TheoryDesign.ListStack.empty 
        LaPToP.TheoryDesign.ListStack.empty
    theorem LaPToP.TheoryDesign.ListStack'.pop_empty_ne :
      LaPToP.TheoryDesign.ListStack'.pop
          LaPToP.TheoryDesign.ListStack.empty 
        LaPToP.TheoryDesign.ListStack.empty
    In the alternative implementation `pop empty ⧧ empty` ... 
  • complete
    theorem LaPToP.TheoryDesign.ListStack'.top_empty_ne :
      LaPToP.TheoryDesign.ListStack'.top
          LaPToP.TheoryDesign.ListStack.empty 
        0
    theorem LaPToP.TheoryDesign.ListStack'.top_empty_ne :
      LaPToP.TheoryDesign.ListStack'.top
          LaPToP.TheoryDesign.ListStack.empty 
        0
    ... and `top empty ⧧ 0`. 
  • complete
    theorem LaPToP.TheoryDesign.pop_empty_unclassified :
      (¬ (T : LaPToP.TheoryDesign.DataStackTheory ),
            T.pop T.empty = T.empty) 
        ¬ (T : LaPToP.TheoryDesign.DataStackTheory ),
            T.pop T.empty  T.empty
    theorem LaPToP.TheoryDesign.pop_empty_unclassified :
      (¬
            (T :
              LaPToP.TheoryDesign.DataStackTheory
                ),
            T.pop T.empty = T.empty) 
        ¬
            (T :
              LaPToP.TheoryDesign.DataStackTheory
                ),
            T.pop T.empty  T.empty
    "So stack theory is incomplete": `pop empty = empty` is neither a theorem
    nor an antitheorem of data-stack theory — it holds in one model and fails in
    another. 
  • complete
    theorem LaPToP.TheoryDesign.top_empty_unclassified :
      (¬ (T : LaPToP.TheoryDesign.DataStackTheory ), T.top T.empty = 0) 
        ¬ (T : LaPToP.TheoryDesign.DataStackTheory ), T.top T.empty  0
    theorem LaPToP.TheoryDesign.top_empty_unclassified :
      (¬
            (T :
              LaPToP.TheoryDesign.DataStackTheory
                ),
            T.top T.empty = 0) 
        ¬
            (T :
              LaPToP.TheoryDesign.DataStackTheory
                ),
            T.top T.empty  0
    Likewise for `top empty = 0`. 
Definition8.4
Group: Hehner's Chapter 7: "the stack, the queue, and the tree ... are presented here as case studies in theory design and implementation", a theory being "a contract between two parties, an implementer and a user". The data theories of Section 7.0 are formalized in LaPToP.TheoryDesign.Stack , SimpleStack , Queue and Tree ; program-stack theory (Section 7.1) in LaPToP.TheoryDesign.ProgramStack . (8)
Group member previews
Preview
Definition 8.1
Loading preview
Group member preview content is loaded from the rendered-fragment cache.
Statement uses 2
Statement dependency previews
Preview
Definition 8.1
Loading preview
Statement dependency preview content is loaded from the rendered-fragment cache.
used by 1L∃∀N

"In the data-stack theory just presented, we have axioms \mathit{empty} : \mathit{stack} and \mathit{pop} : \mathit{stack} \to \mathit{stack}; from them we can prove \mathit{pop}\ \mathit{empty} : \mathit{stack}. ... An implementer is obliged to give a stack for \mathit{pop}\ \mathit{empty}, though it does not matter which one. If we never want to pop an empty stack, then the theory is too strong. ... For most purposes, it is sufficient to be able to push items onto a stack, pop items off, and look at the top item. ... Our simpler data-stack theory introduces the names \mathit{stack}, \mathit{push}, \mathit{pop}, and \mathit{top} with the following four axioms: \mathit{stack} \neq \mathit{null}, \mathit{push}\ s\ x : \mathit{stack}, \mathit{pop}(\mathit{push}\ s\ x) = s, \mathit{top}(\mathit{push}\ s\ x) = x." The design remarks are made concrete: every data-stack theory is a simple one, the list implementation is a model, and there is a model with no empty stack at all — infinite stacks \mathit{nat} \to X, in which every stack is a \mathit{push} ("we never need an empty stack, nor to test if a stack is empty"). "As an engineering activity, theory design is the art of excluding all unwanted implementations while allowing all the others." Uses Definition 8.1 and Theorem 8.2.

Lean code for Definition8.45 declarations
  • structure(7 fields)defined in LaPToP/TheoryDesign/SimpleStack.lean
    complete
    structure LaPToP.TheoryDesign.SimpleStackTheory.{u, v} (X : Type u) :
      Type (max u (v + 1))
    structure LaPToP.TheoryDesign.SimpleStackTheory.{u,
        v}
      (X : Type u) : Type (max u (v + 1))
    The *simple data-stack theory* (aPToP §7.0.2): `stack ⧧ null`,
    `push s x: stack`, `pop (push s x) = s`, `top (push s x) = x`. 
    Stack : Type v
    `stack`. 
    nonempty : Nonempty self.Stack
    `stack ⧧ null`, "so that we can still declare variables of type stack". 
    push : self.Stack  X  self.Stack
    `push s x: stack`. 
    pop : self.Stack  self.Stack
    `pop`; the book drops `pop: stack→stack` so that `pop empty` need not be provided. 
    top : self.Stack  X
    `top`; likewise `top: stack→X` is dropped. 
    pop_push :  (s : self.Stack) (x : X), self.pop (self.push s x) = s
    `pop (push s x) = s`. 
    top_push :  (s : self.Stack) (x : X), self.top (self.push s x) = x
    `top (push s x) = x`. 
  • complete
    def LaPToP.TheoryDesign.SimpleStackTheory.ofDataStack.{u, u_1} {X : Type u}
      (T : LaPToP.TheoryDesign.DataStackTheory X) :
      LaPToP.TheoryDesign.SimpleStackTheory X
    def LaPToP.TheoryDesign.SimpleStackTheory.ofDataStack.{u,
        u_1}
      {X : Type u}
      (T :
        LaPToP.TheoryDesign.DataStackTheory
          X) :
      LaPToP.TheoryDesign.SimpleStackTheory X
    Every data-stack theory is a simple data-stack theory: the simple theory is weaker. 
  • complete
    def LaPToP.TheoryDesign.SimpleStackTheory.listModel :
      LaPToP.TheoryDesign.SimpleStackTheory 
    def LaPToP.TheoryDesign.SimpleStackTheory.listModel :
      LaPToP.TheoryDesign.SimpleStackTheory 
    The list implementation is a model of the simple theory. 
  • complete
    def LaPToP.TheoryDesign.SimpleStackTheory.streamModel.{u} (X : Type u)
      [Inhabited X] : LaPToP.TheoryDesign.SimpleStackTheory X
    def LaPToP.TheoryDesign.SimpleStackTheory.streamModel.{u}
      (X : Type u) [Inhabited X] :
      LaPToP.TheoryDesign.SimpleStackTheory X
    The stream model: stacks are infinite sequences `ℕ → X`; `push` prepends,
    `pop` drops the head, `top` is the head. 
  • complete
    theorem LaPToP.TheoryDesign.SimpleStackTheory.streamModel_every_push.{u}
      (X : Type u) [Inhabited X]
      (e : (LaPToP.TheoryDesign.SimpleStackTheory.streamModel X).Stack) :
       s x,
        (LaPToP.TheoryDesign.SimpleStackTheory.streamModel X).push s x = e
    theorem LaPToP.TheoryDesign.SimpleStackTheory.streamModel_every_push.{u}
      (X : Type u) [Inhabited X]
      (e :
        (LaPToP.TheoryDesign.SimpleStackTheory.streamModel
            X).Stack) :
       s x,
        (LaPToP.TheoryDesign.SimpleStackTheory.streamModel
                X).push
            s x =
          e
    In the stream model every stack is a `push`: there is no empty stack, so
    the strong axiom `push s x ⧧ empty` could not hold for any choice of `empty`.
    "As long as we are given some tree [stack], we can build" what we need. 
Definition8.5
Group: Hehner's Chapter 7: "the stack, the queue, and the tree ... are presented here as case studies in theory design and implementation", a theory being "a contract between two parties, an implementer and a user". The data theories of Section 7.0 are formalized in LaPToP.TheoryDesign.Stack , SimpleStack , Queue and Tree ; program-stack theory (Section 7.1) in LaPToP.TheoryDesign.ProgramStack . (8)
Group member previews
Preview
Definition 8.1
Loading preview
Group member preview content is loaded from the rendered-fragment cache.
Statement uses 2
Statement dependency previews
Preview
Theorem 4.10
Loading preview
Statement dependency preview content is loaded from the rendered-fragment cache.
used by 0L∃∀N

"The queue data structure, also known as a buffer ... is the structure with the motto: the first one in is the first one out. We introduce the syntax \mathit{queue}, \mathit{emptyq}, \mathit{join}, \mathit{leave}, and \mathit{front}." Axioms: \mathit{emptyq} : \mathit{queue}, \mathit{join}\ q\ x : \mathit{queue}; \mathit{join}\ q\ x \neq \mathit{emptyq}, \mathit{join}\ q\ x = \mathit{join}\ r\ y = (q = r \land x = y); queue induction \mathit{emptyq}, \mathit{join}\ B\ X : B \Rightarrow \mathit{queue} : B; and "first in, first out": \mathit{leave}(\mathit{join}\ \mathit{emptyq}\ x) = \mathit{emptyq}, q \neq \mathit{emptyq} \Rightarrow \mathit{leave}(\mathit{join}\ q\ x) = \mathit{join}(\mathit{leave}\ q)\ x, \mathit{front}(\mathit{join}\ \mathit{emptyq}\ x) = x, q \neq \mathit{emptyq} \Rightarrow \mathit{front}(\mathit{join}\ q\ x) = \mathit{front}\ q. The typing axioms q \neq \mathit{emptyq} \Rightarrow \mathit{leave}\ q : \mathit{queue} and q \neq \mathit{emptyq} \Rightarrow \mathit{front}\ q : X "can now be proved" (automatic for a carrier type). Derived: every queue is \mathit{emptyq} or a \mathit{join}, and the item joined to the empty queue stays at the front whatever is joined afterwards. "Data-queue implementation raises no new issues, so we leave it as Exercise 426": lists with \mathit{join}\ q\ x = q ;; [x], \mathit{leave}\ q = q\,[1;..\# q], \mathit{front}\ q = q\,0 are a DataQueueTheory ℤ. Uses Definition 8.1 and Theorem 4.10.

Lean code for Definition8.510 declarations
  • structure(12 fields)defined in LaPToP/TheoryDesign/Queue.lean
    complete
    structure LaPToP.TheoryDesign.DataQueueTheory.{u, v} (X : Type u) :
      Type (max u (v + 1))
    structure LaPToP.TheoryDesign.DataQueueTheory.{u, v}
      (X : Type u) : Type (max u (v + 1))
    A *data-queue theory* over items `X` (aPToP §7.0.3). 
    Queue : Type v
    `queue`, "a bunch consisting of all queues of items of type `X`". 
    emptyq : self.Queue
    `emptyq: queue`, "a queue containing no items". 
    join : self.Queue  X  self.Queue
    `join: queue→X→queue`, "the queue containing the same items plus the one new item". 
    leave : self.Queue  self.Queue
    `leave`, "the queue minus the oldest remaining item". 
    front : self.Queue  X
    `front`, "the oldest remaining item". 
    induction :  (P : self.Queue  Prop),
      P self.emptyq  (∀ (q : self.Queue) (x : X), P q  P (self.join q x))   (q : self.Queue), P q
    Queue induction: `emptyq, join B X: B ⇒ queue: B`. 
    join_ne_emptyq :  (q : self.Queue) (x : X), self.join q x  self.emptyq
    `join q x ⧧ emptyq`. 
    join_inj :  (q r : self.Queue) (x y : X), self.join q x = self.join r y  q = r  x = y
    `join q x = join r y = q=r ∧ x=y`. 
    leave_join_emptyq :  (x : X), self.leave (self.join self.emptyq x) = self.emptyq
    `leave (join emptyq x) = emptyq`. 
    leave_join :  (q : self.Queue) (x : X), q  self.emptyq  self.leave (self.join q x) = self.join (self.leave q) x
    `q⧧emptyq ⇒ leave (join q x) = join (leave q) x`. 
    front_join_emptyq :  (x : X), self.front (self.join self.emptyq x) = x
    `front (join emptyq x) = x`. 
    front_join :  (q : self.Queue) (x : X), q  self.emptyq  self.front (self.join q x) = self.front q
    `q⧧emptyq ⇒ front (join q x) = front q`. 
  • complete
    theorem LaPToP.TheoryDesign.DataQueueTheory.eq_emptyq_or_join.{u, u_1}
      {X : Type u} (T : LaPToP.TheoryDesign.DataQueueTheory X)
      (q : T.Queue) : q = T.emptyq   r x, q = T.join r x
    theorem LaPToP.TheoryDesign.DataQueueTheory.eq_emptyq_or_join.{u,
        u_1}
      {X : Type u}
      (T :
        LaPToP.TheoryDesign.DataQueueTheory X)
      (q : T.Queue) :
      q = T.emptyq   r x, q = T.join r x
    Every queue is `emptyq` or a `join`. 
  • complete
    theorem LaPToP.TheoryDesign.DataQueueTheory.front_foldl.{u, u_1} {X : Type u}
      (T : LaPToP.TheoryDesign.DataQueueTheory X) (l : List X) (q : T.Queue)
      (hq : q  T.emptyq) : T.front (List.foldl T.join q l) = T.front q
    theorem LaPToP.TheoryDesign.DataQueueTheory.front_foldl.{u,
        u_1}
      {X : Type u}
      (T :
        LaPToP.TheoryDesign.DataQueueTheory X)
      (l : List X) (q : T.Queue)
      (hq : q  T.emptyq) :
      T.front (List.foldl T.join q l) =
        T.front q
    Joining items to a nonempty queue does not change its front: the FIFO
    character, iterated. 
  • complete
    theorem LaPToP.TheoryDesign.DataQueueTheory.front_joins.{u, u_1} {X : Type u}
      (T : LaPToP.TheoryDesign.DataQueueTheory X) (x : X) (l : List X) :
      T.front (List.foldl T.join (T.join T.emptyq x) l) = x
    theorem LaPToP.TheoryDesign.DataQueueTheory.front_joins.{u,
        u_1}
      {X : Type u}
      (T :
        LaPToP.TheoryDesign.DataQueueTheory X)
      (x : X) (l : List X) :
      T.front
          (List.foldl T.join
            (T.join T.emptyq x) l) =
        x
    "The first one in is the first one out": the item joined to the empty queue
    stays at the front whatever is joined afterwards. 
  • complete
    def LaPToP.TheoryDesign.ListQueue.emptyq : LaPToP.DataStructures.HList 
    def LaPToP.TheoryDesign.ListQueue.emptyq :
      LaPToP.DataStructures.HList 
    `emptyq = [nil]`. 
  • complete
    def LaPToP.TheoryDesign.ListQueue.join (q : LaPToP.DataStructures.HList )
      (x : ) : LaPToP.DataStructures.HList 
    def LaPToP.TheoryDesign.ListQueue.join
      (q : LaPToP.DataStructures.HList )
      (x : ) : LaPToP.DataStructures.HList 
    `join q x = q;;[x]`: the new item goes to the back. 
  • complete
    def LaPToP.TheoryDesign.ListQueue.leave
      (q : LaPToP.DataStructures.HList ) : LaPToP.DataStructures.HList 
    def LaPToP.TheoryDesign.ListQueue.leave
      (q : LaPToP.DataStructures.HList ) :
      LaPToP.DataStructures.HList 
    `leave q = q [1;..#q]`: drop the front item (`leave emptyq = emptyq`). 
  • complete
    def LaPToP.TheoryDesign.ListQueue.front
      (q : LaPToP.DataStructures.HList ) : 
    def LaPToP.TheoryDesign.ListQueue.front
      (q : LaPToP.DataStructures.HList ) : 
    `front q = q 0` (`front emptyq = 0`). 
  • complete
    theorem LaPToP.TheoryDesign.ListQueue.join_ne_emptyq
      (q : LaPToP.DataStructures.HList ) (x : ) :
      LaPToP.TheoryDesign.ListQueue.join q x 
        LaPToP.TheoryDesign.ListQueue.emptyq
    theorem LaPToP.TheoryDesign.ListQueue.join_ne_emptyq
      (q : LaPToP.DataStructures.HList )
      (x : ) :
      LaPToP.TheoryDesign.ListQueue.join q x 
        LaPToP.TheoryDesign.ListQueue.emptyq
    `join q x ⧧ emptyq`. 
  • complete
    def LaPToP.TheoryDesign.ListQueue.theory :
      LaPToP.TheoryDesign.DataQueueTheory 
    def LaPToP.TheoryDesign.ListQueue.theory :
      LaPToP.TheoryDesign.DataQueueTheory 
    Lists implement data-queue theory. 
Definition8.6
Group: Hehner's Chapter 7: "the stack, the queue, and the tree ... are presented here as case studies in theory design and implementation", a theory being "a contract between two parties, an implementer and a user". The data theories of Section 7.0 are formalized in LaPToP.TheoryDesign.Stack , SimpleStack , Queue and Tree ; program-stack theory (Section 7.1) in LaPToP.TheoryDesign.ProgramStack . (8)
Group member previews
Preview
Definition 8.1
Loading preview
Group member preview content is loaded from the rendered-fragment cache.
Statement uses 3
Statement dependency previews
Preview
Definition 4.9
Loading preview
Statement dependency preview content is loaded from the rendered-fragment cache.
used by 0L∃∀N

"We introduce the syntax \mathit{tree}, \mathit{emptree}, \mathit{graft}, \mathit{left}, \mathit{right}, \mathit{root}. For the purpose of studying trees, we want a strong theory": \mathit{emptree} : \mathit{tree}, \mathit{graft} : \mathit{tree} \to X \to \mathit{tree} \to \mathit{tree}, induction \mathit{emptree}, \mathit{graft}\ B\ X\ B : B \Rightarrow \mathit{tree} : B, \mathit{graft}\ t\ x\ u \neq \mathit{emptree}, \mathit{graft}\ t\ x\ u = \mathit{graft}\ v\ y\ w = (t = v \land x = y \land u = w), \mathit{left}(\mathit{graft}\ t\ x\ u) = t, \mathit{root}(\mathit{graft}\ t\ x\ u) = x, \mathit{right}(\mathit{graft}\ t\ x\ u) = u. "For most programming purposes, the following simpler, weaker theory is sufficient": \mathit{tree} \neq \mathit{null}, \mathit{graft}\ t\ x\ u : \mathit{tree} and the three selector axioms. Derived: every tree is \mathit{emptree} or a \mathit{graft}; the selectors alone make \mathit{graft} injective. The book's implementation by nested lists (\mathit{graft}\ t\ x\ u = [t; x; u], \mathit{left}\ t = t\,0, \mathit{root}\ t = t\,1, \mathit{right}\ t = t\,2) mixes lists and items and is not expressible with the homogeneous lists of Definition 4.9; the implementation here is the inductive type of finite binary trees — the recursive data definition \mathit{tree} = \mathit{emptree}, \mathit{graft}\ \mathit{tree}\ X\ \mathit{tree} as a datatype (cf. Definition 7.5) — with the book's example tree [[[\mathit{nil}]; 2; [[\mathit{nil}]; 5; [\mathit{nil}]]]; 3; [[\mathit{nil}]; 7; [\mathit{nil}]]]. Uses Definition 8.1.

Lean code for Definition8.612 declarations
  • structure(12 fields)defined in LaPToP/TheoryDesign/Tree.lean
    complete
    structure LaPToP.TheoryDesign.DataTreeTheory.{u, v} (X : Type u) :
      Type (max u (v + 1))
    structure LaPToP.TheoryDesign.DataTreeTheory.{u, v}
      (X : Type u) : Type (max u (v + 1))
    A *data-tree theory* over items `X` (aPToP §7.0.4), "a strong theory". 
    Tree : Type v
    `tree`, "a bunch consisting of all finite binary trees of items of type `X`". 
    emptree : self.Tree
    `emptree: tree`, "a tree containing no items". 
    graft : self.Tree  X  self.Tree  self.Tree
    `graft: tree→X→tree→tree`, "the tree with the item at the root and the two given
    trees as left and right subtree". 
    left : self.Tree  self.Tree
    `left`, the left subtree. 
    right : self.Tree  self.Tree
    `right`, the right subtree. 
    root : self.Tree  X
    `root`, the root item. 
    induction :  (P : self.Tree  Prop),
      P self.emptree 
        (∀ (t : self.Tree) (x : X) (u : self.Tree), P t  P u  P (self.graft t x u))   (t : self.Tree), P t
    Tree induction: `emptree, graft B X B: B ⇒ tree: B`. 
    graft_ne_emptree :  (t : self.Tree) (x : X) (u : self.Tree), self.graft t x u  self.emptree
    `graft t x u ⧧ emptree`. 
    graft_inj :  (t : self.Tree) (x : X) (u v : self.Tree) (y : X) (w : self.Tree),
      self.graft t x u = self.graft v y w  t = v  x = y  u = w
    `graft t x u = graft v y w = t=v ∧ x=y ∧ u=w`. 
    left_graft :  (t : self.Tree) (x : X) (u : self.Tree), self.left (self.graft t x u) = t
    `left (graft t x u) = t`. 
    root_graft :  (t : self.Tree) (x : X) (u : self.Tree), self.root (self.graft t x u) = x
    `root (graft t x u) = x`. 
    right_graft :  (t : self.Tree) (x : X) (u : self.Tree), self.right (self.graft t x u) = u
    `right (graft t x u) = u`. 
  • structure(9 fields)defined in LaPToP/TheoryDesign/Tree.lean
    complete
    structure LaPToP.TheoryDesign.SimpleTreeTheory.{u, v} (X : Type u) :
      Type (max u (v + 1))
    structure LaPToP.TheoryDesign.SimpleTreeTheory.{u,
        v}
      (X : Type u) : Type (max u (v + 1))
    The "simpler, weaker" data-tree theory: `tree ⧧ null`, `graft t x u: tree`,
    and the three selector axioms — "we don't really need to be given an empty
    tree ... and we probably don't need tree induction". 
    Tree : Type v
    `tree`. 
    nonempty : Nonempty self.Tree
    `tree ⧧ null`. 
    graft : self.Tree  X  self.Tree  self.Tree
    `graft`. 
    left : self.Tree  self.Tree
    `left`. 
    right : self.Tree  self.Tree
    `right`. 
    root : self.Tree  X
    `root`. 
    left_graft :  (t : self.Tree) (x : X) (u : self.Tree), self.left (self.graft t x u) = t
    `left (graft t x u) = t`. 
    root_graft :  (t : self.Tree) (x : X) (u : self.Tree), self.root (self.graft t x u) = x
    `root (graft t x u) = x`. 
    right_graft :  (t : self.Tree) (x : X) (u : self.Tree), self.right (self.graft t x u) = u
    `right (graft t x u) = u`. 
  • complete
    theorem LaPToP.TheoryDesign.DataTreeTheory.eq_emptree_or_graft.{u, u_1}
      {X : Type u} (T : LaPToP.TheoryDesign.DataTreeTheory X) (t : T.Tree) :
      t = T.emptree   l x r, t = T.graft l x r
    theorem LaPToP.TheoryDesign.DataTreeTheory.eq_emptree_or_graft.{u,
        u_1}
      {X : Type u}
      (T :
        LaPToP.TheoryDesign.DataTreeTheory X)
      (t : T.Tree) :
      t = T.emptree 
         l x r, t = T.graft l x r
    Every tree is `emptree` or a `graft`. 
  • complete
    theorem LaPToP.TheoryDesign.DataTreeTheory.graft_inj_of_selectors.{u, u_1}
      {X : Type u} (T : LaPToP.TheoryDesign.DataTreeTheory X)
      (t u v w : T.Tree) (x y : X) (h : T.graft t x u = T.graft v y w) :
      t = v  x = y  u = w
    theorem LaPToP.TheoryDesign.DataTreeTheory.graft_inj_of_selectors.{u,
        u_1}
      {X : Type u}
      (T :
        LaPToP.TheoryDesign.DataTreeTheory X)
      (t u v w : T.Tree) (x y : X)
      (h : T.graft t x u = T.graft v y w) :
      t = v  x = y  u = w
    The selector axioms alone make `graft` injective, so the second "distinct
    trees" axiom is derivable from them. 
  • complete
    def LaPToP.TheoryDesign.DataTreeTheory.toSimple.{u, u_1} {X : Type u}
      (T : LaPToP.TheoryDesign.DataTreeTheory X) :
      LaPToP.TheoryDesign.SimpleTreeTheory X
    def LaPToP.TheoryDesign.DataTreeTheory.toSimple.{u,
        u_1}
      {X : Type u}
      (T :
        LaPToP.TheoryDesign.DataTreeTheory
          X) :
      LaPToP.TheoryDesign.SimpleTreeTheory X
    Every data-tree theory is a simple one. 
  • inductive(2 constructors, 1 parameter)defined in LaPToP/TheoryDesign/Tree.lean
    complete
    inductive LaPToP.TheoryDesign.BinTree.{u} (X : Type u) : Type u
    inductive LaPToP.TheoryDesign.BinTree.{u}
      (X : Type u) : Type u
    Finite binary trees of items of type `X`: the recursive data definition
    `tree = emptree, graft tree X tree` as a datatype. 
    LaPToP.TheoryDesign.BinTree.emptree.{u} {X : Type u} :
      LaPToP.TheoryDesign.BinTree X
    `emptree`. 
    LaPToP.TheoryDesign.BinTree.graft.{u} {X : Type u}
      (l : LaPToP.TheoryDesign.BinTree X) (x : X)
      (r : LaPToP.TheoryDesign.BinTree X) :
      LaPToP.TheoryDesign.BinTree X
    `graft t x u`. 
  • complete
    def LaPToP.TheoryDesign.BinTree.left.{u} {X : Type u} :
      LaPToP.TheoryDesign.BinTree X  LaPToP.TheoryDesign.BinTree X
    def LaPToP.TheoryDesign.BinTree.left.{u}
      {X : Type u} :
      LaPToP.TheoryDesign.BinTree X 
        LaPToP.TheoryDesign.BinTree X
    `left`; on `emptree` the theory says nothing, and we return `emptree`. 
  • complete
    def LaPToP.TheoryDesign.BinTree.right.{u} {X : Type u} :
      LaPToP.TheoryDesign.BinTree X  LaPToP.TheoryDesign.BinTree X
    def LaPToP.TheoryDesign.BinTree.right.{u}
      {X : Type u} :
      LaPToP.TheoryDesign.BinTree X 
        LaPToP.TheoryDesign.BinTree X
    `right`; on `emptree` we return `emptree`. 
  • complete
    def LaPToP.TheoryDesign.BinTree.root.{u} {X : Type u} [Inhabited X] :
      LaPToP.TheoryDesign.BinTree X  X
    def LaPToP.TheoryDesign.BinTree.root.{u}
      {X : Type u} [Inhabited X] :
      LaPToP.TheoryDesign.BinTree X  X
    `root`; on `emptree` we return the default item. 
  • complete
    def LaPToP.TheoryDesign.BinTree.theory.{u} (X : Type u) [Inhabited X] :
      LaPToP.TheoryDesign.DataTreeTheory X
    def LaPToP.TheoryDesign.BinTree.theory.{u}
      (X : Type u) [Inhabited X] :
      LaPToP.TheoryDesign.DataTreeTheory X
    Binary trees implement data-tree theory. 
  • complete
    def LaPToP.TheoryDesign.BinTree.example₁ : LaPToP.TheoryDesign.BinTree 
    def LaPToP.TheoryDesign.BinTree.example₁ :
      LaPToP.TheoryDesign.BinTree 
    The book's example tree `[[[nil]; 2; [[nil]; 5; [nil]]]; 3; [[nil]; 7; [nil]]]`. 
  • complete
    theorem LaPToP.TheoryDesign.BinTree.example₁_roots :
      LaPToP.TheoryDesign.BinTree.example₁.root = 3 
        LaPToP.TheoryDesign.BinTree.example₁.left.root = 2
    theorem LaPToP.TheoryDesign.BinTree.example₁_roots :
      LaPToP.TheoryDesign.BinTree.example₁.root =
          3 
        LaPToP.TheoryDesign.BinTree.example₁.left.root =
          2
    Its root is `3` and the root of its left subtree is `2`. 
Definition8.7
Group: Hehner's Chapter 7: "the stack, the queue, and the tree ... are presented here as case studies in theory design and implementation", a theory being "a contract between two parties, an implementer and a user". The data theories of Section 7.0 are formalized in LaPToP.TheoryDesign.Stack , SimpleStack , Queue and Tree ; program-stack theory (Section 7.1) in LaPToP.TheoryDesign.ProgramStack . (8)
Group member previews
Preview
Definition 8.1
Loading preview
Group member preview content is loaded from the rendered-fragment cache.
Statement uses 3
Statement dependency previews
Preview
Definition 5.2
Loading preview
Statement dependency preview content is loaded from the rendered-fragment cache.
Used by 2
Reverse dependency previews
Preview
Theorem 8.8
Loading preview
Reverse dependency preview content is loaded from the rendered-fragment cache.
L∃∀N

"Users and implementers of a data structure can freely see and change their own variables, but they cannot freely see or change each other's variables. ... If we need only one stack ... we can obtain an economy of expression and of execution by leaving it implicit." "The simplest version of program-stack theory introduces three names: \mathit{push} (a procedure with parameter of type X), \mathit{pop} (a program), and \mathit{top} (of type X). ... The following two axioms are sufficient: \mathit{top}' = x \Leftarrow \mathit{push}\ x, \mathit{ok} \Leftarrow \mathit{push}\ x.\ \mathit{pop}." A program theory is a structure over a state type with \mathit{push} a parametrized specification, \mathit{pop} a specification and \mathit{top} a state variable, the axioms being refinements. "The second axiom says that a pop undoes a push. In fact, it says that any natural number of pushes are undone by the same number of pops: \mathit{ok} \Leftarrow \mathit{push}\ x.\ \mathit{pop} = \mathit{push}\ x.\ \mathit{ok}.\ \mathit{pop} \Leftarrow \mathit{push}\ x.\ \mathit{push}\ y.\ \mathit{pop}.\ \mathit{pop} ... We can prove things like \mathit{top}' = x \Leftarrow \mathit{push}\ x.\ \mathit{push}\ y.\ \mathit{push}\ z.\ \mathit{pop}.\ \mathit{pop}, which say that when we push something onto the stack, we find it there later at the appropriate time." Both are proved, the first for any number of push–pop pairs. Uses Definition 8.4, Definition 5.2 and Theorem 5.12.

Lean code for Definition8.79 declarations
  • structure(5 fields)defined in LaPToP/TheoryDesign/ProgramStack.lean
    complete
    structure LaPToP.TheoryDesign.ProgramStackTheory.{u, v} (X : Type u)
      (σ : Type v) : Type (max u v)
    structure LaPToP.TheoryDesign.ProgramStackTheory.{u,
        v}
      (X : Type u) (σ : Type v) :
      Type (max u v)
    *Program-stack theory* (aPToP §7.1.0): `push` (a procedure with a parameter),
    `pop` (a program), `top` (a variable), with `top′=x ⇐ push x` and `ok ⇐ push x. pop`. 
    push : X  LaPToP.ProgramTheory.Spec σ
    `push x`, "a procedure with parameter of type `X`". 
    pop : LaPToP.ProgramTheory.Spec σ
    `pop`, "a program". 
    top : σ  X
    `top`, a state variable "of type `X`". 
    top_push :  (x : X), LaPToP.ProgramTheory.Spec.Refines (fun x_1 s' => self.top s' = x) (self.push x)
    `top′=x ⇐ push x`. 
    push_pop :  (x : X), LaPToP.ProgramTheory.Spec.ok.Refines ((self.push x).seq self.pop)
    `ok ⇐ push x. pop`: "a pop undoes a push". 
  • complete
    theorem LaPToP.TheoryDesign.refinesOfEq.{v} {σ : Type v}
      {P Q : LaPToP.ProgramTheory.Spec σ} (h : P = Q) : P.Refines Q
    theorem LaPToP.TheoryDesign.refinesOfEq.{v}
      {σ : Type v}
      {P Q : LaPToP.ProgramTheory.Spec σ}
      (h : P = Q) : P.Refines Q
    A specification refines an equal one. 
  • complete
    theorem LaPToP.TheoryDesign.ProgramStackTheory.push_pop_seq.{u, v} {X : Type u}
      {σ : Type v} (T : LaPToP.TheoryDesign.ProgramStackTheory X σ) (x : X)
      (P : LaPToP.ProgramTheory.Spec σ) :
      P.Refines ((T.push x).seq (T.pop.seq P))
    theorem LaPToP.TheoryDesign.ProgramStackTheory.push_pop_seq.{u,
        v}
      {X : Type u} {σ : Type v}
      (T :
        LaPToP.TheoryDesign.ProgramStackTheory
          X σ)
      (x : X)
      (P : LaPToP.ProgramTheory.Spec σ) :
      P.Refines ((T.push x).seq (T.pop.seq P))
    `P ⇐ push x. pop. P`: a push-pop pair before any specification is harmless. 
  • complete
    def LaPToP.TheoryDesign.ProgramStackTheory.balanced.{u, v} {X : Type u}
      {σ : Type v} (T : LaPToP.TheoryDesign.ProgramStackTheory X σ) :
      List X  LaPToP.ProgramTheory.Spec σ
    def LaPToP.TheoryDesign.ProgramStackTheory.balanced.{u,
        v}
      {X : Type u} {σ : Type v}
      (T :
        LaPToP.TheoryDesign.ProgramStackTheory
          X σ) :
      List X  LaPToP.ProgramTheory.Spec σ
    `push x₁. (push x₂. (… (push xₙ. ok. pop) …). pop). pop`: `n` pushes followed by `n` pops. 
  • complete
    theorem LaPToP.TheoryDesign.ProgramStackTheory.ok_refines_balanced.{u, v}
      {X : Type u} {σ : Type v}
      (T : LaPToP.TheoryDesign.ProgramStackTheory X σ) (xs : List X) :
      LaPToP.ProgramTheory.Spec.ok.Refines (T.balanced xs)
    theorem LaPToP.TheoryDesign.ProgramStackTheory.ok_refines_balanced.{u,
        v}
      {X : Type u} {σ : Type v}
      (T :
        LaPToP.TheoryDesign.ProgramStackTheory
          X σ)
      (xs : List X) :
      LaPToP.ProgramTheory.Spec.ok.Refines
        (T.balanced xs)
    "Any natural number of pushes are undone by the same number of pops": `ok ⇐ balanced xs`. 
  • complete
    theorem LaPToP.TheoryDesign.ProgramStackTheory.ok_refines_push_push_pop_pop.{u,
        v}
      {X : Type u} {σ : Type v}
      (T : LaPToP.TheoryDesign.ProgramStackTheory X σ) (x y : X) :
      LaPToP.ProgramTheory.Spec.ok.Refines
        ((T.push x).seq ((T.push y).seq (T.pop.seq T.pop)))
    theorem LaPToP.TheoryDesign.ProgramStackTheory.ok_refines_push_push_pop_pop.{u,
        v}
      {X : Type u} {σ : Type v}
      (T :
        LaPToP.TheoryDesign.ProgramStackTheory
          X σ)
      (x y : X) :
      LaPToP.ProgramTheory.Spec.ok.Refines
        ((T.push x).seq
          ((T.push y).seq (T.pop.seq T.pop)))
    The book's calculation: `ok ⇐ push x. pop = push x. ok. pop ⇐ push x. push y. pop. pop`. 
  • complete
    theorem LaPToP.TheoryDesign.ProgramStackTheory.refines_balanced_seq.{u, v}
      {X : Type u} {σ : Type v}
      (T : LaPToP.TheoryDesign.ProgramStackTheory X σ) (xs : List X)
      (P : LaPToP.ProgramTheory.Spec σ) : P.Refines ((T.balanced xs).seq P)
    theorem LaPToP.TheoryDesign.ProgramStackTheory.refines_balanced_seq.{u,
        v}
      {X : Type u} {σ : Type v}
      (T :
        LaPToP.TheoryDesign.ProgramStackTheory
          X σ)
      (xs : List X)
      (P : LaPToP.ProgramTheory.Spec σ) :
      P.Refines ((T.balanced xs).seq P)
    A balanced block before a specification is harmless: `P ⇐ balanced xs. P`. 
  • complete
    theorem LaPToP.TheoryDesign.ProgramStackTheory.top_push_push_push_pop_pop.{u, v}
      {X : Type u} {σ : Type v}
      (T : LaPToP.TheoryDesign.ProgramStackTheory X σ) (x y z : X) :
      LaPToP.ProgramTheory.Spec.Refines (fun x_1 s' => T.top s' = x)
        ((T.push x).seq ((T.push y).seq ((T.push z).seq (T.pop.seq T.pop))))
    theorem LaPToP.TheoryDesign.ProgramStackTheory.top_push_push_push_pop_pop.{u,
        v}
      {X : Type u} {σ : Type v}
      (T :
        LaPToP.TheoryDesign.ProgramStackTheory
          X σ)
      (x y z : X) :
      LaPToP.ProgramTheory.Spec.Refines
        (fun x_1 s' => T.top s' = x)
        ((T.push x).seq
          ((T.push y).seq
            ((T.push z).seq
              (T.pop.seq T.pop))))
    "When we push something onto the stack, we find it there later at the
    appropriate time": `top′=x ⇐ push x. push y. push z. pop. pop`. 
  • complete
    theorem LaPToP.TheoryDesign.ProgramStackTheory.top_push_balanced.{u, v}
      {X : Type u} {σ : Type v}
      (T : LaPToP.TheoryDesign.ProgramStackTheory X σ) (x : X)
      (xs : List X) :
      LaPToP.ProgramTheory.Spec.Refines (fun x_1 s' => T.top s' = x)
        ((T.push x).seq (T.balanced xs))
    theorem LaPToP.TheoryDesign.ProgramStackTheory.top_push_balanced.{u,
        v}
      {X : Type u} {σ : Type v}
      (T :
        LaPToP.TheoryDesign.ProgramStackTheory
          X σ)
      (x : X) (xs : List X) :
      LaPToP.ProgramTheory.Spec.Refines
        (fun x_1 s' => T.top s' = x)
        ((T.push x).seq (T.balanced xs))
    Any push is eventually visible: `top′=x ⇐ push x. balanced xs`. 
Theorem8.8
Group: Hehner's Chapter 7: "the stack, the queue, and the tree ... are presented here as case studies in theory design and implementation", a theory being "a contract between two parties, an implementer and a user". The data theories of Section 7.0 are formalized in LaPToP.TheoryDesign.Stack , SimpleStack , Queue and Tree ; program-stack theory (Section 7.1) in LaPToP.TheoryDesign.ProgramStack . (8)
Group member previews
Preview
Definition 8.1
Loading preview
Group member preview content is loaded from the rendered-fragment cache.
Statement uses 3
Statement dependency previews
Preview
Theorem 4.10
Loading preview
Statement dependency preview content is loaded from the rendered-fragment cache.
used by 1L∃∀N

"To implement program-stack theory, we introduce an implementer's variable s : [*X] and define \mathit{push} = \langle x : X \cdot s := s ;; [x] \rangle, \mathit{pop} = s := s\,[0;..\# s - 1], \mathit{top} = s\,(\# s - 1). And, of course, we must show that these definitions satisfy the axioms. We'll do the first axiom (\mathit{top}' = x \Leftarrow \mathit{push}\ x) = (s'(\# s' - 1) = x \Leftarrow s := s ;; [x]) = \top, and leave the other as Exercise 429." Both axioms are proved (the second by (s ;; [x])[0;..\# s] = s), so the list definitions form a ProgramStackTheory. The implementer's state consists of the variable s alone; user variables, which the stack operations leave unchanged, would be added as a product (cf. Definition 6.9). Uses Definition 8.7 and Theorem 4.10.

Lean code for Theorem8.87 declarations
  • structure(1 field)defined in LaPToP/TheoryDesign/ProgramStack.lean
    complete
    structure LaPToP.TheoryDesign.PS.{u} (X : Type u) : Type u
    structure LaPToP.TheoryDesign.PS.{u} (X : Type u) :
      Type u
    The implementer's state: the variable `s: [*X]`. 
    s : LaPToP.DataStructures.HList X
    The implementer's variable `s`. 
  • complete
    def LaPToP.TheoryDesign.ListProgramStack.push.{u} {X : Type u} (x : X) :
      LaPToP.ProgramTheory.Spec (LaPToP.TheoryDesign.PS X)
    def LaPToP.TheoryDesign.ListProgramStack.push.{u}
      {X : Type u} (x : X) :
      LaPToP.ProgramTheory.Spec
        (LaPToP.TheoryDesign.PS X)
    `push x = s:= s;;[x]`. 
  • complete
    def LaPToP.TheoryDesign.ListProgramStack.pop.{u} {X : Type u} :
      LaPToP.ProgramTheory.Spec (LaPToP.TheoryDesign.PS X)
    def LaPToP.TheoryDesign.ListProgramStack.pop.{u}
      {X : Type u} :
      LaPToP.ProgramTheory.Spec
        (LaPToP.TheoryDesign.PS X)
    `pop = s:= s[0;..#s–1]`. 
  • complete
    def LaPToP.TheoryDesign.ListProgramStack.top.{u} {X : Type u} [Inhabited X]
      (st : LaPToP.TheoryDesign.PS X) : X
    def LaPToP.TheoryDesign.ListProgramStack.top.{u}
      {X : Type u} [Inhabited X]
      (st : LaPToP.TheoryDesign.PS X) : X
    `top = s(#s–1)`. 
  • complete
    theorem LaPToP.TheoryDesign.ListProgramStack.top_push.{u} {X : Type u}
      [Inhabited X] (x : X) :
      LaPToP.ProgramTheory.Spec.Refines
        (fun x_1 st' => LaPToP.TheoryDesign.ListProgramStack.top st' = x)
        (LaPToP.TheoryDesign.ListProgramStack.push x)
    theorem LaPToP.TheoryDesign.ListProgramStack.top_push.{u}
      {X : Type u} [Inhabited X] (x : X) :
      LaPToP.ProgramTheory.Spec.Refines
        (fun x_1 st' =>
          LaPToP.TheoryDesign.ListProgramStack.top
              st' =
            x)
        (LaPToP.TheoryDesign.ListProgramStack.push
          x)
    The first axiom, the book's calculation: `(top′=x ⇐ push x) = (s′(#s′–1) = x ⇐ s:= s;;[x]) = ⊤`. 
  • complete
    theorem LaPToP.TheoryDesign.ListProgramStack.push_pop.{u} {X : Type u} (x : X) :
      LaPToP.ProgramTheory.Spec.ok.Refines
        ((LaPToP.TheoryDesign.ListProgramStack.push x).seq
          LaPToP.TheoryDesign.ListProgramStack.pop)
    theorem LaPToP.TheoryDesign.ListProgramStack.push_pop.{u}
      {X : Type u} (x : X) :
      LaPToP.ProgramTheory.Spec.ok.Refines
        ((LaPToP.TheoryDesign.ListProgramStack.push
              x).seq
          LaPToP.TheoryDesign.ListProgramStack.pop)
    The second axiom, Exercise 429: `ok ⇐ push x. pop`. 
  • complete
    def LaPToP.TheoryDesign.ListProgramStack.theory.{u} (X : Type u)
      [Inhabited X] :
      LaPToP.TheoryDesign.ProgramStackTheory X (LaPToP.TheoryDesign.PS X)
    def LaPToP.TheoryDesign.ListProgramStack.theory.{u}
      (X : Type u) [Inhabited X] :
      LaPToP.TheoryDesign.ProgramStackTheory X
        (LaPToP.TheoryDesign.PS X)
    Lists implement program-stack theory. 
Definition8.9
Group: Hehner's Chapter 7: "the stack, the queue, and the tree ... are presented here as case studies in theory design and implementation", a theory being "a contract between two parties, an implementer and a user". The data theories of Section 7.0 are formalized in LaPToP.TheoryDesign.Stack , SimpleStack , Queue and Tree ; program-stack theory (Section 7.1) in LaPToP.TheoryDesign.ProgramStack . (8)
Group member previews
Preview
Definition 8.1
Loading preview
Group member preview content is loaded from the rendered-fragment cache.
Statement uses 3
Statement dependency previews
Preview
Definition 6.10
Loading preview
Statement dependency preview content is loaded from the rendered-fragment cache.
used by 0L∃∀N

"A slightly fancier program-stack theory introduces two more names: \mathit{mkempty} (a program to make the stack empty) and \mathit{isempty} (a binary variable to say whether the stack is empty). Letting x : X, the axioms are \mathit{top}' = x \land \neg\mathit{isempty}' \Leftarrow \mathit{push}\ x, \mathit{ok} \Leftarrow \mathit{push}\ x.\ \mathit{pop}, \mathit{isempty}' \Leftarrow \mathit{mkempty}" — the list implementation satisfies them too. "The program-stack theory we presented first can be weakened and still retain its stack character. We must keep the axiom \mathit{top}' = x \Leftarrow \mathit{push}\ x but we do not need the composition \mathit{push}\ x.\ \mathit{pop} to leave all variables unchanged. We do require that any natural number of pushes followed by the same number of pops gives back the original top. The axioms are \mathit{top}' = \mathit{top} \Leftarrow \mathit{balance}, \mathit{balance} \Leftarrow \mathit{ok}, \mathit{balance} \Leftarrow \mathit{push}\ x.\ \mathit{balance}.\ \mathit{pop}, where \mathit{balance} is a specification that helps in writing the axioms, but is not an addition to the theory, and does not need to be implemented." Proved: \mathit{top}' = \mathit{top} after any number of pushes followed by the same number of pops, and that the strong theory implies the weak one (with \mathit{balance} := \mathit{ok}). The book's remark that the weak theory "allows an implementation in which popping ... marks the last item as garbage" is not formalized. The axiom \mathbf{screen}!\ \text{“error”} \Leftarrow \mathit{mkempty}.\ \mathit{pop} mentioned for robustness is a Chapter 9 notation, cf. Definition 6.10. Uses Definition 8.7 and Theorem 8.8.

Lean code for Definition8.910 declarations
  • structure(extends 1, 9 fields)defined in LaPToP/TheoryDesign/ProgramStack.lean
    complete
    structure LaPToP.TheoryDesign.FancyProgramStackTheory.{u, v} (X : Type u)
      (σ : Type v) : Type (max u v)
    structure LaPToP.TheoryDesign.FancyProgramStackTheory.{u,
        v}
      (X : Type u) (σ : Type v) :
      Type (max u v)
    The fancy theory adds `mkempty` ("a program to make the stack empty") and
    `isempty` ("a binary variable to say whether the stack is empty"), with
    `top′=x ∧ ¬isempty′ ⇐ push x`, `ok ⇐ push x. pop`, `isempty′ ⇐ mkempty`. 
    • LaPToP.TheoryDesign.ProgramStackTheory X σ
    push : X  LaPToP.ProgramTheory.Spec σ
    Inherited from
    1. LaPToP.TheoryDesign.ProgramStackTheory
    pop : LaPToP.ProgramTheory.Spec σ
    Inherited from
    1. LaPToP.TheoryDesign.ProgramStackTheory
    top : σ  X
    Inherited from
    1. LaPToP.TheoryDesign.ProgramStackTheory
    top_push :  (x : X), LaPToP.ProgramTheory.Spec.Refines (fun x_1 s' => self.top s' = x) (self.push x)
    Inherited from
    1. LaPToP.TheoryDesign.ProgramStackTheory
    push_pop :  (x : X), LaPToP.ProgramTheory.Spec.ok.Refines ((self.push x).seq self.pop)
    Inherited from
    1. LaPToP.TheoryDesign.ProgramStackTheory
    mkempty : LaPToP.ProgramTheory.Spec σ
    `mkempty`, a program. 
    isempty : σ  Prop
    `isempty`, a binary variable. 
    not_isempty_push :  (x : X), LaPToP.ProgramTheory.Spec.Refines (fun x s' => ¬self.isempty s') (self.push x)
    `¬isempty′ ⇐ push x` (with `top′=x ⇐ push x` inherited). 
    isempty_mkempty : LaPToP.ProgramTheory.Spec.Refines (fun x s' => self.isempty s') self.mkempty
    `isempty′ ⇐ mkempty`. 
  • complete
    theorem LaPToP.TheoryDesign.FancyProgramStackTheory.top_push_not_isempty.{u, v}
      {X : Type u} {σ : Type v}
      (T : LaPToP.TheoryDesign.FancyProgramStackTheory X σ) (x : X) :
      LaPToP.ProgramTheory.Spec.Refines
        (fun x_1 s' => T.top s' = x  ¬T.isempty s') (T.push x)
    theorem LaPToP.TheoryDesign.FancyProgramStackTheory.top_push_not_isempty.{u,
        v}
      {X : Type u} {σ : Type v}
      (T :
        LaPToP.TheoryDesign.FancyProgramStackTheory
          X σ)
      (x : X) :
      LaPToP.ProgramTheory.Spec.Refines
        (fun x_1 s' =>
          T.top s' = x  ¬T.isempty s')
        (T.push x)
    The book's first fancy axiom in one piece: `top′=x ∧ ¬isempty′ ⇐ push x`. 
  • complete
    def LaPToP.TheoryDesign.ListProgramStack.mkempty.{u} {X : Type u} :
      LaPToP.ProgramTheory.Spec (LaPToP.TheoryDesign.PS X)
    def LaPToP.TheoryDesign.ListProgramStack.mkempty.{u}
      {X : Type u} :
      LaPToP.ProgramTheory.Spec
        (LaPToP.TheoryDesign.PS X)
    `mkempty = s:= [nil]`. 
  • complete
    def LaPToP.TheoryDesign.ListProgramStack.isempty.{u} {X : Type u}
      (st : LaPToP.TheoryDesign.PS X) : Prop
    def LaPToP.TheoryDesign.ListProgramStack.isempty.{u}
      {X : Type u}
      (st : LaPToP.TheoryDesign.PS X) : Prop
    `isempty = (s = [nil])`. 
  • complete
    def LaPToP.TheoryDesign.ListProgramStack.fancyTheory.{u} (X : Type u)
      [Inhabited X] :
      LaPToP.TheoryDesign.FancyProgramStackTheory X
        (LaPToP.TheoryDesign.PS X)
    def LaPToP.TheoryDesign.ListProgramStack.fancyTheory.{u}
      (X : Type u) [Inhabited X] :
      LaPToP.TheoryDesign.FancyProgramStackTheory
        X (LaPToP.TheoryDesign.PS X)
    Lists implement the fancy theory too. 
  • structure(8 fields)defined in LaPToP/TheoryDesign/ProgramStack.lean
    complete
    structure LaPToP.TheoryDesign.WeakProgramStackTheory.{u, v} (X : Type u)
      (σ : Type v) : Type (max u v)
    structure LaPToP.TheoryDesign.WeakProgramStackTheory.{u,
        v}
      (X : Type u) (σ : Type v) :
      Type (max u v)
    The weak theory keeps `top′=x ⇐ push x` "but we do not need the composition
    `push x. pop` to leave all variables unchanged. We do require that any natural
    number of pushes followed by the same number of pops gives back the original
    top": `top′=top ⇐ balance`, `balance ⇐ ok`, `balance ⇐ push x. balance. pop`,
    "where `balance` is a specification that helps in writing the axioms, but is
    not an addition to the theory, and does not need to be implemented". 
    push : X  LaPToP.ProgramTheory.Spec σ
    `push x`. 
    pop : LaPToP.ProgramTheory.Spec σ
    `pop`. 
    top : σ  X
    `top`. 
    balance : LaPToP.ProgramTheory.Spec σ
    `balance`, an auxiliary specification. 
    top_push :  (x : X), LaPToP.ProgramTheory.Spec.Refines (fun x_1 s' => self.top s' = x) (self.push x)
    `top′=x ⇐ push x`. 
    top_balance : LaPToP.ProgramTheory.Spec.Refines (fun s s' => self.top s' = self.top s) self.balance
    `top′=top ⇐ balance`. 
    balance_ok : self.balance.Refines LaPToP.ProgramTheory.Spec.ok
    `balance ⇐ ok`. 
    balance_push_pop :  (x : X), self.balance.Refines ((self.push x).seq (self.balance.seq self.pop))
    `balance ⇐ push x. balance. pop`. 
  • complete
    def LaPToP.TheoryDesign.WeakProgramStackTheory.balanced.{u, v} {X : Type u}
      {σ : Type v} (T : LaPToP.TheoryDesign.WeakProgramStackTheory X σ) :
      List X  LaPToP.ProgramTheory.Spec σ
    def LaPToP.TheoryDesign.WeakProgramStackTheory.balanced.{u,
        v}
      {X : Type u} {σ : Type v}
      (T :
        LaPToP.TheoryDesign.WeakProgramStackTheory
          X σ) :
      List X  LaPToP.ProgramTheory.Spec σ
    `n` pushes followed by `n` pops, as for the strong theory. 
  • complete
    theorem LaPToP.TheoryDesign.WeakProgramStackTheory.balance_refines_balanced.{u,
        v}
      {X : Type u} {σ : Type v}
      (T : LaPToP.TheoryDesign.WeakProgramStackTheory X σ) (xs : List X) :
      T.balance.Refines (T.balanced xs)
    theorem LaPToP.TheoryDesign.WeakProgramStackTheory.balance_refines_balanced.{u,
        v}
      {X : Type u} {σ : Type v}
      (T :
        LaPToP.TheoryDesign.WeakProgramStackTheory
          X σ)
      (xs : List X) :
      T.balance.Refines (T.balanced xs)
    `balance ⇐ balanced xs`. 
  • complete
    theorem LaPToP.TheoryDesign.WeakProgramStackTheory.top_balanced.{u, v}
      {X : Type u} {σ : Type v}
      (T : LaPToP.TheoryDesign.WeakProgramStackTheory X σ) (xs : List X) :
      LaPToP.ProgramTheory.Spec.Refines (fun s s' => T.top s' = T.top s)
        (T.balanced xs)
    theorem LaPToP.TheoryDesign.WeakProgramStackTheory.top_balanced.{u,
        v}
      {X : Type u} {σ : Type v}
      (T :
        LaPToP.TheoryDesign.WeakProgramStackTheory
          X σ)
      (xs : List X) :
      LaPToP.ProgramTheory.Spec.Refines
        (fun s s' => T.top s' = T.top s)
        (T.balanced xs)
    "Any natural number of pushes followed by the same number of pops gives
    back the original top": `top′=top ⇐ balanced xs`. 
  • complete
    def LaPToP.TheoryDesign.ProgramStackTheory.toWeak.{u, v} {X : Type u}
      {σ : Type v} (T : LaPToP.TheoryDesign.ProgramStackTheory X σ) :
      LaPToP.TheoryDesign.WeakProgramStackTheory X σ
    def LaPToP.TheoryDesign.ProgramStackTheory.toWeak.{u,
        v}
      {X : Type u} {σ : Type v}
      (T :
        LaPToP.TheoryDesign.ProgramStackTheory
          X σ) :
      LaPToP.TheoryDesign.WeakProgramStackTheory
        X σ
    The strong theory implies the weak one, with `balance := ok`.