<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
 <head>
  <title>Lambda Calculus for EuLisp</title>
  <style type="text/css">
  </style>
 </head>
 <body>
  <h1>Lambda Calculus for EuLisp</h1>

  <p>This consists of library written in the form of an <a
  href="http://www.aiai.ed.ac.uk/~jeff/lisp/eulisp.html">EuLisp</a>
  module (<a
  href="Modules/lambda-calculus.em"><code>lambda-calculus.em</code></a>) and
  an application (<a href="lc"><code>lc</code></a>) which uses this
  library and implements a simple user interface.</p>

  <h2>1. Data structure used to represent lambda-terms</h2>

  <p>The data structure which represents the lambda-terms is a class
  hierarchy.</p>

  <p>The base class is <code>&lt;lambda-term&gt;</code>. It is an
  abstract class with no slots.</p>

  <p>Variables are represented by the class
  <code>&lt;variable&gt;</code>, which derives from
  <code>&lt;lambda-term&gt;</code>. It has one required slot,
  <code>name</code>, with reader <code>name</code> and writer
  <code>alpha-rename</code>.</p>

  <p>Applications are stored by the <code>&lt;application&gt;</code>
  class, also derived from <code>&lt;lambda-term&gt;</code>. It has
  two read-only required slots, <code>M</code> and <code>N</code>.
  (Slots are not typed, but it is assumed that these slots will
  contain <code>&lt;lambda-term&gt;</code> objects.)</p>

  <p>Finally the <code>&lt;abstraction&gt;</code> class, also a
  descendent of <code>&lt;lambda-term&gt;</code>, is used to store
  abstractions. It has two read-only required slots,
  <code>parameter</code> (intended for a <code>&lt;variable&gt;</code>
  object) and <code>body</code> (intended for any
  <code>&lt;lambda-term&gt;</code> object)</p>

  <h2>2. Alpha-renaming of lambda-terms</h2>

  <p>Implementing alpha-renaming of variables is trivial with the
  structure described above -- the inclusion of the following line in
  the definition of the <code>&lt;variable&gt;</code> class'
  <code>name</code> slot declares a function <code>alpha-rename</code>
  taking as arguments a <code>&lt;variable&gt;</code> and a new
  name:</p>

  <pre>      writer: alpha-rename</pre>

  <h2>3. Lambda-term substitution</h2>

  <p>This is implemented by a set of methods with the following signature:</p>

  <pre>  (defgeneric substitute ((term &lt;lambda-term&gt;) (search &lt;variable&gt;) (replace &lt;lambda-term&gt;)))</pre>

  <p>For variables, the implementation of this method returns
  <code>replace</code> if the variable is <code>search</code> and
  itself otherwise:</p>

  <pre>  (defmethod substitute ((term &lt;variable&gt;) (search &lt;variable&gt;) (replace &lt;lambda-term&gt;))
    (if (eq term search) replace term))</pre>

  <p>For applications and abstractions, the implementations simply
  recurse into the <code>M</code> and <code>N</code> terms and the
  <code>body</code> term respectively:</p>

  <pre>  (defmethod substitute ((term &lt;application&gt;) (search &lt;variable&gt;) (replace &lt;lambda-term&gt;))
    (application (substitute (M term) search replace) (substitute (N term) search replace)))

  (defmethod substitute ((term &lt;abstraction&gt;) (search &lt;variable&gt;) (replace &lt;lambda-term&gt;))
    (abstraction (parameter term) (substitute (body term) search replace)))</pre>

  <h3>Name clashes</h3>

  <p>The prevention of name clashes is implemented as a separate
  function, imaginatively called <code>clean-name-clashes</code>. This
  is called by the interface code after calling
  <code>substitute</code>.</p>

  <h2>4. One step beta-reduction of a redex</h2>

  <p>This is implemented using methods on the
  <code>&lt;lambda-term&gt;</code> class. Using different methods on
  each subclass, the behaviour specific to each term type is
  automatically used. The current implementation hard codes knowledge
  of abstractions in the application term, but if more types were
  introduced then a greater level of abstraction could be introduced
  to remove even that.</p>

  <p>See the <code>beta-reduce-step</code> and
  <code>beta-reduced-p</code> generic functions.</p>

  <h2>5. General beta-reduction of a lambda-term</h2>

  <p>This is implemented simply by calling
  <code>beta-reduce-step</code> until <code>beta-reduced-p</code>
  returns false.</p>

  <h3>Heuristic to try to avoid infinite reduction</h3>

  <p>The interpreter code implements this heuristic by running the
  beta reduction on a separate thread and waiting for five seconds on
  the UI thread to see if the reduction terminates. If it does not,
  then the user is prompted to see if he wants to stop the
  reduction.</p>

  <p>If the reduction is stopped then a condition is signalled on the
  reduction thread, causing it to abort.</p>

  <p>In non-interactive mode (<code>=f file</code> argument) reduction
  never aborts. Scripts run using <code>lc</code> should therefore
  avoid trying to reduce expressions that have no normal form. In
  interactive mode, expressions can be forced to automatically abort
  after five seconds (without a prompt) by using the <code>=a</code>
  command line argument.</p>

  <h2>Examples of Testing</h2>

  <p>The file <a href="test.pl"><code>test.pl</code></a> tests the
  code by running it with some specific expressions, capturing the
  output, and comparing it to a reference rendering.</p> <!-- XXX -->

  <h2>Appendix A. lc Manual</h2>

  <p>To run lc, simply type <code>./lc</code> in its directory. You
  must have <a
  href="http://www.bath.ac.uk/~masrjb/Sources/euscheme.html">euscheme</a>
  installed.</p>

  <p>The following commands are supported:</p>
  <dl>
   <dt>S</dt> <dd>returns S.</dd>
   <dt>[R/V]S</dt> <dd>returns a new expression consisting of S, where
   every mention of variable V is replaced by R. The variables are
   then renamed to remove any name clashes in the new expression.
   (This may affect variables in other expressions, such as S
   itself.)</dd>
   <dt>reduce S</dt> <dd>returns a new expression that is the beta
   reduced form of S. Since this may not terminate, you may be
   prompted to abort the reduction in interactive mode. In batch mode
   care should be taken to not reduce expressions that do not
   terminate.</dd>
   <dt>step S</dt> <dd>returns a new expression that is S, beta
   reduced once.</dd>
   <dt>print S</dt> <dd>prints and returns S.</dd>
   <dt>copy S</dt> <dd>returns a deep copy of S.</dd>
   <dt>variables S</dt> <dd>lists the unbound variables in S and
   returns S.</dd>
   <dt>variable n S</dt> <dd>returns the nth unbound variable in
   S.</dd>
   <dt>rename V a</dt> <dd>alpha-renames V to a.</dd>
  </dl>
  <p>where:</p>
  <ul>
   <li>S is any Lambda Calculus expression or reference, e.g. R or (Lx.yz)a</li>
   <li>R is any Lambda Calculus reference, e.g. R</li>
   <li>V is any Lambda Calculus reference that is a variable, e.g. R</li>
   <li>n is a number, and a is a letter.</li>
  </ul>
  <p>Any command may be prefixed by R= to assign the result of the
  command to R. Note that the variables used in lambda expressions are
  in a different namespace to the references. Also bear in mind that
  two variables with the same name may not actually be the same
  variable if they were not created in the same expression.</p>
  <p>Lines prefixed with a '#' symbol are ignored.</p>
  <h3>Examples:</h3>
  <pre>
  &gt; A=Lx.xy
  Lx.xy
  &gt; B=aa
  aa
  &gt; variables B
  variable 0: a
  aa
  &gt; a=variable 0 B
  a
  &gt; B=[A/a]B
  (Lx.xy)(Lx.xy)
  &gt; reduce B
  yy
  &gt; B
  (Lx.yy)(Lx.yy)
  </pre>
  <p>To exit the Lambda Calculus interpreter, type: quit</p>

  <h2>Appendix B. Errors found</h2>

  <p>During the development of this utility, I found three errors in
  the <a
  href="http://tkb.mpl.com/~tkb/software/docs/defn-0.99.pdf">EuLisp
  0.99 spec</a>:</p>

  <ol>
   <li>Section 12.1.8.2, under <code>init-option</code>, contains a
   typo: <q>to then</q> should be <q>to the</q>.</li>
   <li>Section 13.4.3.2, the definition of the <code>and</code>
   special form, has an inconsistency. The prose says
   <code>(and)</code> should reduce to <code>()</code> while the
   rewrite rules say it should reduce to <code>#t</code>.</li>
   <li>Section A.1.5.2, the examples for the <code>binary&lt;</code>
   method, misspells the name of the method four times.</li>
  </ol>

  <p>I also found ten bugs in the <code>euscheme</code>
  interpreter.</p>

  <ol>
   <li><code>&lt;char&gt;</code> should be
   <code>&lt;character&gt;</code> according to the EuLisp 0.99
   spec.</li>

   <li>Defining a method <code>apply</code> causes the debugger to
   fail to respond to its commands (such as <code>:help</code>). This
   may be because the debugger executes in the scope in which the
   condition was raised, instead of the scope of the
   <code>thread.em</code> module, and therefore it is affected by
   redefinitions of functions it uses.</li>

   <li>The <code>(defgeneric)</code> and <code>(generic-lambda)</code>
   defining forms expect the keyword <code>method:</code> but EuLisp
   0.99 spec says that they should expect <code>method</code> (without
   the colon).</li>

   <li>The interpreter doesn't implement EuLisp 0.99's streams.</li>

   <li>The order of evaluation of arguments is right-to-left but
   section 13.2.4.4 of the EuLisp 0.99 specification says it should be
   left to right.</li>

   <li>The debugger's backtraces frequently do not list the actual
   functions being executed, instead listing the
   <code>let-binding</code> forms encountered.</li>

   <li>Compilation errors do not list line numbers, making debugging
   long programs a matter of trial and error.</li>

   <li>The documentation says that the form of arguments to
   <code>euscheme</code> is
   <pre>euscheme [-opts] [filename] [args...]</pre>
   However, it doesn't say that <code>args</code> cannot start with a
   hyphen (<code>-</code>). This limitation makes it impossible to
   write shell scripts that accept conventional arguments using
   <code>euscheme</code>.</li>

   <li><code>&lt;thread&gt;</code> is an abstract class. One has to
   instantiate a <code>&lt;simple-thread&gt;</code> object when one
   wishes to make a new thread.</li>

   <li><code>&lt;simple-thread&gt;</code>'s slot is called
   <code>function:</code> but the EuLisp 0.99 spec says that
   <code>&lt;thread&gt;</code>'s slot should be called
   <code>init-function</code>.</li>
  </ol>

  <h2>Appendix C. Source</h2>

  <p>The source for the following files is included:</p>

  <dl>
   <dt><a href="lc"><code>lc</code></a></dt>
   <dd>A Lambda Calculus shell script interpreter written in EuLisp
   that uses euscheme as its own interpreter. This is the core of the
   program, it just handles the command line arguments and then passes
   the results of this to the interface module.</dd>
   <dt><a href="Modules/lambda-calculus-interface.em"><code>lambda-calculus-interface.em</code></a></dt>
   <dd>The main read-eval-print loop. Handles reading from standard
   input and from files. Reads one line at a time and passes each line
   to the interpreter module for processing</dd>
   <dt><a href="Modules/lambda-calculus-interpreter.em"><code>lambda-calculus-interpreter.em</code></a></dt>
   <dd>The command parser, this module parses the input from the user
   and passes it to the core Lambda Calculus code.</dd>
   <dt><a href="Modules/lambda-calculus.em"><code>lambda-calculus.em</code></a></dt>
   <dd>This module implements the majority of the actual coursework.</dd>
   <dt><a href="Modules/lambda-calculus-tokeniser.em"><code>lambda-calculus-tokeniser.em</code></a></dt>
   <dd>In order to fully interpret lambda term expressions, this
   program uses first a tokeniser, this module, followed by a parser,
   the next module. These work together to handle nested expressions,
   implied brackets, and the like.</dd>
   <dt><a href="Modules/lambda-calculus-parser.em"><code>lambda-calculus-parser.em</code></a></dt>
   <dd>The parser part of the lambda term expression parser.</dd>
   <dt><a href="Modules/utilities.em"><code>utilities.em</code></a></dt>
   <dd>A group of reasonably generic utilities used by the rest of the
   program.</dd>
   <dt><a href="test.pl"><code>test.pl</code></a></dt>
   <dd>A test script written in Perl (not EuLisp so that any EuLisp
   errors affecting the code do not affect the test script in the same
   way).</dd>
  </dl>
  <p>All code is distributed under the terms of the <a
  href="LICENSE">GPL</a>.</p>
 </body>
</html>


