doc-src/Logics/Sequents.tex
author wenzelm
Thu, 29 Apr 2010 16:55:22 +0200
changeset 36505 79c1d2bbe5a9
parent 7160 1135f3f8782c
child 42637 381fdcab0f36
permissions -rw-r--r--
ProofContext.read_const: allow for type constraint (for fixed variable); added proof command 'write' to introduce concrete syntax within a proof body;

%% $Id$
\chapter{Defining A Sequent-Based Logic}
\label{chap:sequents}

\underscoreon %this file contains the @ character

The Isabelle theory \texttt{Sequents.thy} provides facilities for using
sequent notation in users' object logics. This theory allows users to
easily interface the surface syntax of sequences with an underlying
representation suitable for higher-order unification.

\section{Concrete syntax of sequences}

Mathematicians and logicians have used sequences in an informal way
much before proof systems such as Isabelle were created. It seems
sensible to allow people using Isabelle to express sequents and
perform proofs in this same informal way, and without requiring the
theory developer to spend a lot of time in \ML{} programming.

By using {\tt Sequents.thy}
appropriately, a logic developer can allow users to refer to sequences
in several ways:
%
\begin{itemize}
\item A sequence variable is any alphanumeric string with the first
 character being a \verb%$% sign. 
So, consider the sequent \verb%$A |- B%, where \verb%$A%
is intended to match a sequence of zero or more items.
 
\item A sequence with unspecified sub-sequences and unspecified or
individual items is written as a comma-separated list of regular
variables (representing items), particular items, and
sequence variables, as in  
\begin{ttbox}
$A, B, C, $D(x) |- E
\end{ttbox}
Here both \verb%$A% and \verb%$D(x)%
are allowed to match any subsequences of items on either side of the
two items that match $B$ and $C$.  Moreover, the sequence matching
\verb%$D(x)% may contain occurrences of~$x$.

\item An empty sequence can be represented by a blank space, as in
\verb? |- true?.
\end{itemize}

These syntactic constructs need to be assimilated into the object
theory being developed. The type that we use for these visible objects
is given the name {\tt seq}.
A {\tt seq} is created either by the empty space, a {\tt seqobj} or a
{\tt seqobj} followed by a {\tt seq}, with a comma between them. A
{\tt seqobj} is either an item or a variable representing a
sequence. Thus, a theory designer can specify a function that takes
two sequences and returns a meta-level proposition by giving it the
Isabelle type \verb|[seq, seq] => prop|.

This is all part of the concrete syntax, but one may wish to
exploit Isabelle's higher-order abstract syntax by actually having a
different, more powerful {\em internal} syntax.



\section{ Basis}

One could opt to represent sequences as first-order objects (such as
simple lists), but this would not allow us to use many facilities
Isabelle provides for matching.  By using a slightly more complex
representation, users of the logic can reap many benefits in
facilities for proofs and ease of reading logical terms.

A sequence can be represented as a function --- a constructor for
further sequences --- by defining a binary {\em abstract} function
\verb|Seq0'| with type \verb|[o,seq']=>seq'|, and translating a
sequence such as \verb|A, B, C| into
\begin{ttbox}
\%s. Seq0'(A, SeqO'(B, SeqO'(C, s)))  
\end{ttbox}
This sequence can therefore be seen as a constructor 
for further sequences. The constructor \verb|Seq0'| is never given a
value, and therefore it is not possible to evaluate this expression
into a basic value.

Furthermore, if we want to represent the sequence \verb|A, $B, C|,
we note that \verb|$B| already represents a sequence, so we can use
\verb|B| itself to refer to the function, and therefore the sequence
can be mapped to the internal form:
\verb|%s. SeqO'(A, B(SeqO'(C, s)))|.

So, while we wish to continue with the standard, well-liked {\em
external} representation of sequences, we can represent them {\em
internally} as functions of type \verb|seq'=>seq'|.


\section{Object logics}

Recall that object logics are defined by mapping elements of
particular types to the Isabelle type \verb|prop|, usually with a
function called {\tt Trueprop}. So, an object
logic proposition {\tt P} is matched to the Isabelle proposition
{\tt Trueprop(P)}\@.  The name of the function is often hidden, so the
user just sees {\tt P}\@. Isabelle is eager to make types match, so it
inserts {\tt Trueprop} automatically when an object of type {\tt prop}
is expected. This mechanism can be observed in most of the object
logics which are direct descendants of {\tt Pure}.

In order to provide the desired syntactic facilities for sequent
calculi, rather than use just one function that maps object-level
propositions to meta-level propositions, we use two functions, and
separate internal from the external representation. 

These functions need to be given a type that is appropriate for the particular
form of sequents required: single or multiple conclusions.  So
multiple-conclusion sequents (used in the LK logic) can be
specified by the following two definitions, which are lifted from the inbuilt
{\tt Sequents/LK.thy}:
\begin{ttbox}
 Trueprop       :: two_seqi
 "@Trueprop"    :: two_seqe   ("((_)/ |- (_))" [6,6] 5)
\end{ttbox}
%
where the types used are defined in {\tt Sequents.thy} as
abbreviations:
\begin{ttbox}
 two_seqi = [seq'=>seq', seq'=>seq'] => prop
 two_seqe = [seq, seq] => prop
\end{ttbox}

The next step is to actually create links into the low-level parsing
and pretty-printing mechanisms, which map external and internal
representations. These functions go below the user level and capture
the underlying structure of Isabelle terms in \ML{}\@.  Fortunately the
theory developer need not delve in this level; {\tt Sequents.thy}
provides the necessary facilities. All the theory developer needs to
add in the \ML{} section is a specification of the two translation
functions:
\begin{ttbox}
ML
val parse_translation = [("@Trueprop",Sequents.two_seq_tr "Trueprop")];
val print_translation = [("Trueprop",Sequents.two_seq_tr' "@Trueprop")];
\end{ttbox}

In summary: in the logic theory being developed, the developer needs
to specify the types for the internal and external representation of
the sequences, and use the appropriate parsing and pretty-printing
functions. 

\section{What's in \texttt{Sequents.thy}}

Theory \texttt{Sequents.thy} makes many declarations that you need to know
about: 
\begin{enumerate}
\item The Isabelle types given below, which can be used for the
constants that map object-level sequents and meta-level propositions:
%
\begin{ttbox}
 single_seqe = [seq,seqobj] => prop
 single_seqi = [seq'=>seq',seq'=>seq'] => prop
 two_seqi    = [seq'=>seq', seq'=>seq'] => prop
 two_seqe    = [seq, seq] => prop
 three_seqi  = [seq'=>seq', seq'=>seq', seq'=>seq'] => prop
 three_seqe  = [seq, seq, seq] => prop
 four_seqi   = [seq'=>seq', seq'=>seq', seq'=>seq', seq'=>seq'] => prop
 four_seqe   = [seq, seq, seq, seq] => prop
\end{ttbox}

The \verb|single_| and \verb|two_| sets of mappings for internal and
external representations are the ones used for, say single and
multiple conclusion sequents. The other functions are provided to
allow rules that manipulate more than two functions, as can be seen in
the inbuilt object logics.

\item An auxiliary syntactic constant has been
defined that directly maps a sequence to its internal representation:
\begin{ttbox}
"@Side"  :: seq=>(seq'=>seq')     ("<<(_)>>")
\end{ttbox}
Whenever a sequence (such as \verb|<< A, $B, $C>>|) is entered using this
syntax, it is translated into the appropriate internal representation.  This
form can be used only where a sequence is expected.

\item The \ML{} functions \texttt{single\_tr}, \texttt{two\_seq\_tr},
  \texttt{three\_seq\_tr}, \texttt{four\_seq\_tr} for parsing, that is, the
  translation from external to internal form.  Analogously there are
  \texttt{single\_tr'}, \texttt{two\_seq\_tr'}, \texttt{three\_seq\_tr'},
  \texttt{four\_seq\_tr'} for pretty-printing, that is, the translation from
  internal to external form.  These functions can be used in the \ML{} section
  of a theory file to specify the translations to be used.  As an example of
  use, note that in {\tt LK.thy} we declare two identifiers:
\begin{ttbox}
val parse_translation =
    [("@Trueprop",Sequents.two_seq_tr "Trueprop")];
val print_translation =
    [("Trueprop",Sequents.two_seq_tr' "@Trueprop")];
\end{ttbox}
The given parse translation will be applied whenever a \verb|@Trueprop|
constant is found, translating using \verb|two_seq_tr| and inserting the
constant \verb|Trueprop|.  The pretty-printing translation is applied
analogously; a term that contains \verb|Trueprop| is printed as a
\verb|@Trueprop|.
\end{enumerate}