{- \section{Introduction}

In this document, we prove the correctness of insertion sort.

\subsection{Preliminaries}

In the sections below, we rely on various definitions stated in the
following separate documents:
-}

--#include "Sorting/predikatlogik.alfa"

--#include "Sorting/satslogik.alfa"

--#include "Sorting/decide.alfa"

--#include "Sorting/nat.alfa"

{- \section{Miscellaneuos definitions and lemmas}

Here we define what a list is, what it means for a list to be sorted (ordered)
and how to insert a new element at the right position in a sorted list.

-}

List (A::Set) :: Set
  = data Nil | Cons (x::A) (xs::List A)

singleton (A::Set)(x::A) :: List A
  = Cons@_ x Nil@_

IsLeAll (x::Nat)(xs::List Nat) :: Prop
  = case xs of {
      (Nil) -> Triviality;
      (Cons x' xs') -> And (LeNat x x') (IsLeAll x xs');}

IsSorted (xs::List Nat) :: Prop
  = case xs of {
      (Nil) -> Triviality;
      (Cons x xs') -> And (IsLeAll x xs') (IsSorted xs');}

{-
Regarding the above definition of what it means for a list to be sorted, it is
worth noting that, for empty lists, there is nothing to prove, and for
non-empty lists, there are two things to prove.
-}

insert (x::Nat)(xs::List Nat) :: List Nat
  = case xs of {
      (Nil) -> singleton Nat x;
      (Cons x' xs') -> ifLt (List Nat) x x' (Cons@_ x xs) (Cons@_ x' (insert x xs'));}

IsLeFirst (a::Nat)
          (x::Nat)
          (xs::List Nat)
          (ax::LeNat a x)
          (p::IsSorted (Cons@_ x xs))
  :: IsLeAll a (Cons@_ x xs)
  = case xs of {
      (Nil) ->
        let ndgoal :: IsLeAll a (Cons@_ x Nil@_)
              = AndIntro (LeNat a x) (IsLeAll a Nil@_)
                  (let ndgoal :: LeNat a x
                         = ax
                   in  ndgoal)
                  (let ndgoal :: IsLeAll a Nil@_
                         = trivial
                   in  ndgoal)
        in  ndgoal;
      (Cons x' xs') ->
        let ndgoal :: IsLeAll a (Cons@_ x (Cons@_ x' xs'))
              = AndIntro (LeNat a x) (IsLeAll a (Cons@_ x' xs'))
                  (let ndgoal :: LeNat a x
                         = ax
                   in  ndgoal)
                  (let ndgoal :: IsLeAll a (Cons@_ x' xs')
                         = AndElim (IsLeAll x (Cons@_ x' xs')) (IsSorted (Cons@_ x' xs'))
                             (IsLeAll a (Cons@_ x' xs'))
                             (let ndgoal :: IsSorted (Cons@_ x xs)
                                    = p
                              in  ndgoal)
                             (\(h::IsLeAll x (Cons@_ x' xs')) ->
                              \(h'::IsSorted (Cons@_ x' xs')) ->
                              let ndgoal :: IsLeAll a (Cons@_ x' xs')
                                    = AndElim (LeNat x x') (IsLeAll x xs')
                                        (IsLeAll a (Cons@_ x' xs'))
                                        (let ndgoal :: And (LeNat x x') (IsLeAll x xs')
                                               = h
                                         in  ndgoal)
                                        (\(h0::LeNat x x') ->
                                         \(h1::IsLeAll x xs') ->
                                         let ndgoal :: IsLeAll a (Cons@_ x' xs')
                                               = IsLeFirst a x' xs'
                                                   (let ndgoal :: LeNat a x'
                                                          = letrans a x x'
                                                              (let ndgoal :: LeNat a x
                                                                     = ax
                                                               in  ndgoal)
                                                              (let ndgoal :: LeNat x x'
                                                                     = h0
                                                               in  ndgoal)
                                                    in  ndgoal)
                                                   (let ndgoal :: IsSorted (Cons@_ x' xs')
                                                          = h'
                                                    in  ndgoal)
                                         in  ndgoal)
                              in  ndgoal)
                   in  ndgoal)
        in  ndgoal;}

ThInsertInSorted (x::Nat)(xs::List Nat)(p::IsSorted xs)
  :: IsSorted (insert x xs)
  = case xs of {
      (Nil) ->
        let ndgoal :: IsSorted (insert x Nil@_)
              = AndIntro (IsLeAll x Nil@_) (IsSorted Nil@_)
                  (let ndgoal :: IsLeAll x Nil@_
                         = trivial
                   in  ndgoal)
                  (let ndgoal :: IsSorted Nil@_
                         = trivial
                   in  ndgoal)
        in  ndgoal;
      (Cons x' xs') ->
        ifLtCase (List Nat) (\(h::List Nat) -> IsSorted h) x x'
          (Cons@_ x (Cons@_ x' xs'))
          (Cons@_ x' (insert x xs'))
          (\(h::LeNat x x') ->
           let ndgoal :: IsSorted (Cons@_ x (Cons@_ x' xs'))
                 = AndIntro (IsLeAll x (Cons@_ x' xs')) (IsSorted (Cons@_ x' xs'))
                     (let ndgoal :: IsLeAll x (Cons@_ x' xs')
                            = IsLeFirst x x' xs'
                                (let ndgoal :: LeNat x x'
                                       = h
                                 in  ndgoal)
                                (let ndgoal :: IsSorted (Cons@_ x' xs')
                                       = p
                                 in  ndgoal)
                      in  ndgoal)
                     (let ndgoal :: IsSorted (Cons@_ x' xs')
                            = p
                      in  ndgoal)
           in  ndgoal)
          (\(h::Not (LeNat x x')) ->
           let indhyp :: IsSorted (insert x xs')
                 = let ndgoal :: IsSorted (insert x xs')
                         = ThInsertInSorted x xs'
                             (let ndgoal :: IsSorted xs'
                                    = And2Elim (IsLeAll x' xs') (IsSorted xs')
                                        (let ndgoal :: And (IsLeAll x' xs') (IsSorted xs')
                                               = p
                                         in  ndgoal)
                              in  ndgoal)
                   in  ndgoal
               lemma1 :: LeNat x' x
                 = leSym x x' h
               lemma2 (x'::Nat)(x::Nat)(xs'::List Nat)(px::LeNat x' x)(pxs::IsLeAll x' xs')
                 :: IsLeAll x' (insert x xs')
                 = case xs' of {
                     (Nil) ->
                       let ndgoal :: IsLeAll x' (insert x Nil@_)
                             = AndIntro (LeNat x' x) (IsLeAll x' Nil@_) px trivial
                       in  ndgoal;
                     (Cons x0 xs0) ->
                       ifLtCase (List Nat) (\(h'::List Nat) -> IsLeAll x' h') x x0
                         (Cons@_ x (Cons@_ x0 xs0))
                         (Cons@_ x0 (insert x xs0))
                         (\(h'::LeNat x x0) ->
                          let ndgoal :: IsLeAll x' (Cons@_ x (Cons@_ x0 xs0))
                                = AndIntro (LeNat x' x) (IsLeAll x' (Cons@_ x0 xs0))
                                    (let ndgoal :: LeNat x' x
                                           = px
                                     in  ndgoal)
                                    (let ndgoal :: IsLeAll x' (Cons@_ x0 xs0)
                                           = pxs
                                     in  ndgoal)
                          in  ndgoal)
                         (\(h'::Not (LeNat x x0)) ->
                          let ndgoal :: IsLeAll x' (Cons@_ x0 (insert x xs0))
                                = AndElim (LeNat x' x0) (IsLeAll x' xs0)
                                    (IsLeAll x' (Cons@_ x0 (insert x xs0)))
                                    (let ndgoal :: And (LeNat x' x0) (IsLeAll x' xs0)
                                           = pxs
                                     in  ndgoal)
                                    (\(h0::LeNat x' x0) ->
                                     \(h1::IsLeAll x' xs0) ->
                                     let ndgoal :: IsLeAll x' (Cons@_ x0 (insert x xs0))
                                           = AndIntro (LeNat x' x0) (IsLeAll x' (insert x xs0))
                                               (let ndgoal :: LeNat x' x0
                                                      = h0
                                                in  ndgoal)
                                               (let ndgoal :: IsLeAll x' (insert x xs0)
                                                      = lemma2 x' x xs0
                                                          (let ndgoal :: LeNat x' x
                                                                 = px
                                                           in  ndgoal)
                                                          (let ndgoal :: IsLeAll x' xs0
                                                                 = h1
                                                           in  ndgoal)
                                                in  ndgoal)
                                     in  ndgoal)
                          in  ndgoal);}
           in  let ndgoal :: IsSorted (Cons@_ x' (insert x xs'))
                     = AndIntro (IsLeAll x' (insert x xs')) (IsSorted (insert x xs'))
                         (let ndgoal :: IsLeAll x' (insert x xs')
                                = lemma2 x' x xs'
                                    (let ndgoal :: LeNat x' x
                                           = lemma1
                                     in  ndgoal)
                                    (let ndgoal :: IsLeAll x' xs'
                                           = And1Elim (IsLeAll x' xs') (IsSorted xs')
                                               (let ndgoal :: And (IsLeAll x' xs') (IsSorted xs')
                                                      = p
                                                in  ndgoal)
                                     in  ndgoal)
                          in  ndgoal)
                         (let ndgoal :: IsSorted (insert x xs')
                                = indhyp
                          in  ndgoal)
               in  ndgoal);}

{- \section{Definitions and lemmas relating to permutations}
-}

count (x::Nat)(xs::List Nat) :: Nat
  = case xs of {
      (Nil) -> Zero@_;
      (Cons x' xs') -> ifEq Nat x x' (Succ@_ (count x xs')) (count x xs');}

Permutation (xs::List Nat)(ys::List Nat) :: Prop
  = ForAll Nat (\(n::Nat) -> EqNat (count n xs) (count n ys))

ThPermNil :: Permutation Nil@_ Nil@_
  = let ndgoal :: Permutation Nil@_ Nil@_
          = ForAllIntro Nat (\(n::Nat) -> EqNat (count n Nil@_) (count n Nil@_))
              (\(any::Nat) ->
               let ndgoal :: EqNat (count any Nil@_) (count any Nil@_)
                     = trivial
               in  ndgoal)
    in  ndgoal

ThPermCons (x::Nat)(ys::List Nat)(zs::List Nat)(p::Permutation ys zs)
  :: Permutation (Cons@_ x ys) (Cons@_ x zs)
  = {-#H#-}ForAllIntro Nat
             (\(n::Nat) -> EqNat (count n (Cons@_ x ys)) (count n (Cons@_ x zs)))
             (\(n::Nat) ->
              ifEqCase Nat (\(h::Nat) -> EqNat h (count n (Cons@_ x zs))) n x
                (Succ@_ (count n ys))
                (count n ys)
                (\(h::EqNat n x) ->
                 ifEqCase Nat (\(h'::Nat) -> EqNat (Succ@_ (count n ys)) h') n x
                   (Succ@_ (count n zs))
                   (count n zs)
                   (\(h'::EqNat n x) ->
                    ForAllElim Nat (\(h0::Nat) -> EqNat (count h0 ys) (count h0 zs)) n p)
                   (\(h'::Not (EqNat n x)) ->
                    AbsurdityElim (EqNat (Succ@_ (count n ys)) (count n zs))
                      (ImpliesElim (EqNat n x) Absurdity h' h)))
                (\(h::Not (EqNat n x)) ->
                 ifEqCase Nat (\(h'::Nat) -> EqNat (count n ys) h') n x (Succ@_ (count n zs))
                   (count n zs)
                   (\(h'::EqNat n x) ->
                    AbsurdityElim (EqNat (count n ys) (Succ@_ (count n zs)))
                      (ImpliesElim (EqNat n x) Absurdity h h'))
                   (\(h'::Not (EqNat n x)) ->
                    ForAllElim Nat (\(h0::Nat) -> EqNat (count h0 ys) (count h0 zs)) n p)))

ThPermTrans (xs::List Nat)
            (ys::List Nat)
            (zs::List Nat)
            (xy::Permutation xs ys)
            (yz::Permutation ys zs)
  :: Permutation xs zs
  = ForAllIntro Nat (\(n::Nat) -> EqNat (count n xs) (count n zs))
      (\(any::Nat) ->
       trans (count any xs) (count any ys) (count any zs)
         (ForAllElim Nat (\(h::Nat) -> EqNat (count h xs) (count h ys)) any xy)
         (ForAllElim Nat (\(h::Nat) -> EqNat (count h ys) (count h zs)) any yz))

ThPermSwap (x1::Nat)(x2::Nat)(xs::List Nat)
  :: Permutation (Cons@_ x1 (Cons@_ x2 xs)) (Cons@_ x2 (Cons@_ x1 xs))
  = {-#H#-}ForAllIntro Nat
             (\(n::Nat) ->
              EqNat (count n (Cons@_ x1 (Cons@_ x2 xs))) (count n (Cons@_ x2 (Cons@_ x1 xs))))
             (\(any::Nat) ->
              ifEqCase Nat (\(h'::Nat) -> EqNat h' (count any (Cons@_ x2 (Cons@_ x1 xs)))) any
                x1
                (Succ@_ (count any (Cons@_ x2 xs)))
                (count any (Cons@_ x2 xs))
                (\(h'::EqNat any x1) ->
                 ifEqCase Nat (\(h::Nat) -> EqNat (Succ@_ (count any (Cons@_ x2 xs))) h) any x2
                   (Succ@_ (count any (Cons@_ x1 xs)))
                   (count any (Cons@_ x1 xs))
                   (\(h::EqNat any x2) ->
                    ifEqCase Nat (\(h0::Nat) -> EqNat h0 (count any (Cons@_ x1 xs))) any x2
                      (Succ@_ (count any xs))
                      (count any xs)
                      (\(h0::EqNat any x2) ->
                       ifEqCase Nat (\(h1::Nat) -> EqNat (Succ@_ (count any xs)) h1) any x1
                         (Succ@_ (count any xs))
                         (count any xs)
                         (\(h1::EqNat any x1) -> refl (count any xs))
                         (\(h1::Not (EqNat any x1)) ->
                          AbsurdityElim (EqNat (Succ@_ (count any xs)) (count any xs))
                            (ImpliesElim (EqNat any x1) Absurdity h1 h')))
                      (\(h0::Not (EqNat any x2)) ->
                       AbsurdityElim (EqNat (count any xs) (count any (Cons@_ x1 xs)))
                         (ImpliesElim (EqNat any x2) Absurdity h0 h)))
                   (\(h::Not (EqNat any x2)) ->
                    ifEqCase Nat (\(h0::Nat) -> EqNat (Succ@_ (count any (Cons@_ x2 xs))) h0) any x1
                      (Succ@_ (count any xs))
                      (count any xs)
                      (\(h0::EqNat any x1) ->
                       ifEqCase Nat (\(h1::Nat) -> EqNat h1 (count any xs)) any x2
                         (Succ@_ (count any xs))
                         (count any xs)
                         (\(h1::EqNat any x2) ->
                          AbsurdityElim (EqNat (Succ@_ (count any xs)) (count any xs))
                            (ImpliesElim (EqNat any x2) Absurdity h h1))
                         (\(h1::Not (EqNat any x2)) -> refl (count any xs)))
                      (\(h0::Not (EqNat any x1)) ->
                       AbsurdityElim (EqNat (Succ@_ (count any (Cons@_ x2 xs))) (count any xs))
                         (ImpliesElim (EqNat any x1) Absurdity h0 h'))))
                (\(h'::Not (EqNat any x1)) ->
                 ifEqCase Nat (\(h0::Nat) -> EqNat (count any (Cons@_ x2 xs)) h0) any x2
                   (Succ@_ (count any (Cons@_ x1 xs)))
                   (count any (Cons@_ x1 xs))
                   (\(h0::EqNat any x2) ->
                    ifEqCase Nat (\(h::Nat) -> EqNat h (Succ@_ (count any (Cons@_ x1 xs)))) any x2
                      (Succ@_ (count any xs))
                      (count any xs)
                      (\(h::EqNat any x2) ->
                       ifEqCase Nat (\(h1::Nat) -> EqNat (count any xs) h1) any x1
                         (Succ@_ (count any xs))
                         (count any xs)
                         (\(h1::EqNat any x1) ->
                          AbsurdityElim (EqNat (count any xs) (Succ@_ (count any xs)))
                            (ImpliesElim (EqNat any x1) Absurdity h' h1))
                         (\(h1::Not (EqNat any x1)) -> refl (count any xs)))
                      (\(h::Not (EqNat any x2)) ->
                       AbsurdityElim (EqNat (count any xs) (Succ@_ (count any (Cons@_ x1 xs))))
                         (ImpliesElim (EqNat any x2) Absurdity h h0)))
                   (\(h::Not (EqNat any x2)) ->
                    ifEqCase Nat (\(h0::Nat) -> EqNat h0 (count any (Cons@_ x1 xs))) any x2
                      (Succ@_ (count any xs))
                      (count any xs)
                      (\(h0::EqNat any x2) ->
                       AbsurdityElim (EqNat (Succ@_ (count any xs)) (count any (Cons@_ x1 xs)))
                         (ImpliesElim (EqNat any x2) Absurdity h h0))
                      (\(h0::Not (EqNat any x2)) ->
                       ifEqCase Nat (\(h1::Nat) -> EqNat (count any xs) h1) any x1
                         (Succ@_ (count any xs))
                         (count any xs)
                         (\(h1::EqNat any x1) ->
                          AbsurdityElim (EqNat (count any xs) (Succ@_ (count any xs)))
                            (ImpliesElim (EqNat any x1) Absurdity h' h1))
                         (\(h1::Not (EqNat any x1)) -> refl (count any xs))))))

ThPermInsert (x::Nat)(xs::List Nat) :: Permutation (Cons@_ x xs) (insert x xs)
  = case xs of {
      (Nil) ->
        ForAllIntro Nat
          (\(n::Nat) -> EqNat (count n (Cons@_ x Nil@_)) (count n (insert x Nil@_)))
          (\(any::Nat) -> refl (count any (Cons@_ x Nil@_)));
      (Cons x' xs') ->
        ifLtCase (List Nat) (\(h::List Nat) -> Permutation (Cons@_ x (Cons@_ x' xs')) h)
          x
          x'
          (Cons@_ x (Cons@_ x' xs'))
          (Cons@_ x' (insert x xs'))
          (\(h::LeNat x x') ->
           ForAllIntro Nat
             (\(n::Nat) ->
              EqNat (count n (Cons@_ x (Cons@_ x' xs'))) (count n (Cons@_ x (Cons@_ x' xs'))))
             (\(any::Nat) -> refl (count any (Cons@_ x (Cons@_ x' xs')))))
          (\(h::Not (LeNat x x')) ->
           let indhyp :: Permutation (Cons@_ x xs') (insert x xs')
                 = ThPermInsert x xs'
           in  let it :: Permutation (Cons@_ x (Cons@_ x' xs')) (Cons@_ x' (insert x xs'))
                     = ThPermTrans (Cons@_ x (Cons@_ x' xs')) (Cons@_ x' (Cons@_ x xs'))
                         (Cons@_ x' (insert x xs'))
                         (ThPermSwap x x' xs')
                         (ThPermCons x' (Cons@_ x xs') (insert x xs') indhyp)
               in  it);}

{-
\section{The sorting algorithm, the correctness criterion and
the correctness proof}
-}

sort (xs::List Nat) :: List Nat
  = case xs of {
      (Nil) -> Nil@_;
      (Cons x xs') -> insert x (sort xs');}

SortSpec (xs::List Nat)(ys::List Nat) :: Prop
  = And (Permutation xs ys) (IsSorted ys)

-- %% Although SortLemma is only used in ThSortIsCorrect, I made it global to be able to specify linearization properties for it.

SortLemma (x::Nat)(xs'::List Nat)(h::Permutation xs' (sort xs'))
  :: Permutation (Cons@_ x xs') (sort (Cons@_ x xs'))
  = let ndgoal :: Permutation (Cons@_ x xs') (sort (Cons@_ x xs'))
          = ThPermTrans (Cons@_ x xs') (Cons@_ x (sort xs')) (sort (Cons@_ x xs'))
              (let ndgoal :: Permutation (Cons@_ x xs') (Cons@_ x (sort xs'))
                     = ThPermCons x xs' (sort xs')
                         (let ndgoal :: Permutation xs' (sort xs')
                                = h
                          in  ndgoal)
               in  ndgoal)
              (let ndgoal :: Permutation (Cons@_ x (sort xs')) (sort (Cons@_ x xs'))
                     = ThPermInsert x (sort xs')
               in  ndgoal)
    in  ndgoal

ThSortIsCorrect (xs::List Nat) :: SortSpec xs (sort xs)
  = case xs of {
      (Nil) ->
        let ndgoal :: SortSpec Nil@_ (sort Nil@_)
              = AndIntro (Permutation Nil@_ (sort Nil@_)) (IsSorted (sort Nil@_))
                  (let ndgoal :: Permutation Nil@_ (sort Nil@_)
                         = ThPermNil
                   in  ndgoal)
                  (let ndgoal :: IsSorted (sort Nil@_)
                         = trivial
                   in  ndgoal)
        in  ndgoal;
      (Cons x xs') ->
        let indhyp :: SortSpec xs' (sort xs')
              = ThSortIsCorrect xs'
        in  let ndgoal :: SortSpec (Cons@_ x xs') (sort (Cons@_ x xs'))
                  = AndElim (Permutation xs' (sort xs')) (IsSorted (sort xs'))
                      (SortSpec (Cons@_ x xs') (sort (Cons@_ x xs')))
                      (let ndgoal :: SortSpec xs' (sort xs')
                             = indhyp
                       in  ndgoal)
                      (\(h::Permutation xs' (sort xs')) ->
                       \(h'::IsSorted (sort xs')) ->
                       let ndgoal :: SortSpec (Cons@_ x xs') (sort (Cons@_ x xs'))
                             = AndIntro (Permutation (Cons@_ x xs') (sort (Cons@_ x xs')))
                                 (IsSorted (sort (Cons@_ x xs')))
                                 (let ndgoal :: Permutation (Cons@_ x xs') (sort (Cons@_ x xs'))
                                        = SortLemma x xs'
                                            (let ndgoal :: Permutation xs' (sort xs')
                                                   = h
                                             in  ndgoal)
                                  in  ndgoal)
                                 (let ndgoal :: IsSorted (sort (Cons@_ x xs'))
                                        = ThInsertInSorted x (sort xs')
                                            (let ndgoal :: IsSorted (sort xs')
                                                   = h'
                                             in  ndgoal)
                                  in  ndgoal)
                       in  ndgoal)
            in  ndgoal;}

-- \section{A simple corollary}

ThSorting
  :: ForAll (List Nat)
       (\(xs::List Nat) -> Exists (List Nat) (\(ys::List Nat) -> SortSpec xs ys))
  = let ndgoal
          :: ForAll (List Nat)
               (\(xs::List Nat) -> Exists (List Nat) (\(ys::List Nat) -> SortSpec xs ys))
          = ForAllIntro (List Nat)
              (\(xs::List Nat) -> Exists (List Nat) (\(ys::List Nat) -> SortSpec xs ys))
              (\(xs::List Nat) ->
               let ndgoal :: Exists (List Nat) (\(ys::List Nat) -> SortSpec xs ys)
                     = ExistsIntro (List Nat) (\(ys::List Nat) -> SortSpec xs ys) (sort xs)
                         (let ndgoal :: SortSpec xs (sort xs)
                                = ThSortIsCorrect xs
                          in  ndgoal)
               in  ndgoal)
    in  ndgoal

sortfun :: List Nat -> List Nat
  = \(xs::List Nat) -> sort xs

ThSorting2 =
  ExistsIntro (List Nat -> List Nat)
    (\(f::List Nat -> List Nat) ->
     ForAll (List Nat) (\(xs::List Nat) -> SortSpec xs (f xs)))
    sortfun
    (ForAllIntro (List Nat) (\(xs::List Nat) -> SortSpec xs (sort xs))
       (\(any::List Nat) -> ThSortIsCorrect any))
{-# Alfa hiding on
var "if" hide 2
con "Nil" as "[]"
con "Cons" infix rightassoc 5 as ":"
var "ThPermTrans" hide 3
var "ThPermCons" hide 3
var "ThPermInsert" hide 2
var "ThInsertInSorted" hide 2
var "Permutation" infix 4 as "~" with symbolfont
var "List" mixfix 0 as "[_]"
var "IsLeFirst" hide 3
var "singleton" hide 1 mixfix 0 as "[_]"
var "listInd" hide 2
var "SortLemma" hide 2
 #-}
{-# GF Eng insert x xs = mkPN (["the list with"]++x.s!pnv++["inserted into"]++xs.s!pnv) #-}
{-# GF Eng IsLeAll x xs = mkSent (x.s!pnv++["is less than or equal to all the elements of"]++xs.s!pnv) #-}
{-# GF Eng IsLeFirst a x xs ax p =
  mkText (ax.s!text++"."++p.s!text++
          [". This means that "]++
          a.s!pnv++["is less than or equal to all the elements of the list with"]++
          x.s!pnv++["prepended to"]++xs.s!pnv) #-}
{-# GF Eng SortLemma x xs' h =
  mkText (h.s!text++[". Use SortLemma"]) #-}
{-# GF Eng ThInsertInSorted x xs p =
  mkText (p.s!text++[". Use the correctness of insertion"]) #-}
{-# GF Eng ThPermNil  = mkThm ["the permutation of empty list theorem"] #-}
{-# GF Eng ThPermCons x ys zs p =
  mkText (p.s!text++
          [". We can now use the theorem about prepending an element to permutations"]) #-}
{-# GF Eng ThPermTrans xs ys zs xy yz = 
  mkText (indent("·"++xy.s!text++"."++newParagraph++"·"++yz.s!text)++
          [". By the transitivity of the permutation relation,"]++
          zs.s!pnv++"is a permutation of"++xs.s!pnv) #-}
{-# GF Eng ThPermInsert x xs = mkThm ["the theorem that inserting yields a permutation of prepending"] #-}
{-# GF Sve IsLeAll x xs = mkSent (x.s!pn++["är mindre än alla element i"]++xs.s!pn) #-}
{-# GF Sve CCCons x xs = mkPN (["listan med"]++x.s!pn++["insatt först i"]++xs.s!pn) en #-}
{-# GF Sve singleton A x = mkPN (["enelementslistan med"]++x.s!pn) en #-}
{-# GF Sve CCNil  = mkPN ["den tomma listan"] en #-}
{-# GF Sve List A = {s = tbl {n => ("list"+nomReg1!n)++"av" ++ A.s ! (cn pl)} ; form = CN en} #-}
{-# GF Eng ThSortIsCorrect xs = mkThm(["the correctness of insertion sort applied to"]++xs.s!pnv) #-}
{-# GF Eng ThSorting  = mkThm ["a sorting theorem"] #-}
{-# GF Eng SortSpec xs ys = mkSent(ys.s!pnv++["is a sorted version of"]++xs.s!pnv) #-}
{-# GF Eng sort xs = mkPN(["insertion sort applied to"]++xs.s!pnv) #-}
{-# GF Eng sortfun xs = mkPN(["insertion sort"]) #-}
{-# GF Eng List A = mkCN(tbl {n=>("list"+nomReg!n)++"of"++A.s!(cn pl)}) #-}
{-# GF Eng Permutation xs ys = mkSent(ys.s!pnv++["is a permutation of"]++xs.s!pnv) #-}
{-# GF Eng count x xs = mkPN(["the number of occurences of"]++x.s!pnv++"in"++xs.s!pnv) #-}
{-# GF Eng singleton A x = mkPN(["the singleton list containing"]++x.s!pnv) #-}
{-# GF Eng IsSorted xs = mkSent (xs.s!pnv ++ ["is sorted"]) #-}
{-# GF Eng CCCons x xs = mkPN (["the list with"]++x.s!pnv++["prepended to"]++xs.s!pnv) #-}
{-# GF Eng CCNil  = mkPN ["the empty list"] #-}
