<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://msmvps.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Angel "Java" Lopez : Proyectos de Código Abierto, C Sharp</title><link>http://msmvps.com/blogs/lopez/archive/tags/Proyectos+de+C_F300_digo+Abierto/C+Sharp/default.aspx</link><description>Tags: Proyectos de Código Abierto, C Sharp</description><dc:language>en</dc:language><generator>CommunityServer 2008.5 SP2 (Build: 40407.4157)</generator><item><title>AjCoreLisp y MinimaLisp, un intérprete Lisp mínimo</title><link>http://msmvps.com/blogs/lopez/archive/2010/05/04/ajcorelisp_2D00_and_2D00_minimalisp_2D00_a_2D00_minimal_2D00_lisp_2D00_interpreter_2D00_implementation.aspx</link><pubDate>Tue, 04 May 2010 09:47:46 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1764833</guid><dc:creator>lopez</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/lopez/rsscomments.aspx?PostID=1764833</wfw:commentRss><comments>http://msmvps.com/blogs/lopez/archive/2010/05/04/ajcorelisp_2D00_and_2D00_minimalisp_2D00_a_2D00_minimal_2D00_lisp_2D00_interpreter_2D00_implementation.aspx#comments</comments><description>&lt;p&gt;Como mencioné en:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://ajlopez.wordpress.com/2010/01/04/ajlisp-family-implementing-lisp-interpreters-in-c/" target="_blank"&gt;AjLisp family: Implementing Lisp Interpreters in C#&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;estuve trabajando en dos intérpretes Lisp: &lt;strong&gt;AjLisp&lt;/strong&gt; y &lt;strong&gt;AjSharpure&lt;/strong&gt; (un intérprete tipo Clojure). Pero quería explorar cuál es el núcleo del lenguaje, la mímima parte que debería ser implementada, para tener un intérprete Lisp.&lt;/p&gt;  &lt;p&gt;Entonces, escribí &lt;strong&gt;AjCoreLisp&lt;/strong&gt;. Pueden bajarlo del proyecto Google Code&lt;/p&gt;  &lt;p&gt;&lt;a title="http://code.google.com/p/ajlisp/source/browse/#svn/trunk/AjCoreLisp" href="http://code.google.com/p/ajlisp/source/browse/#svn/trunk/AjCoreLisp"&gt;http://code.google.com/p/ajlisp/source/browse/#svn/trunk/AjCoreLisp&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Está implementado en C#. La solución:&lt;/p&gt;  &lt;p&gt;&lt;img src="http://www.ajlopez.com/images/articles2/ajcorelisp01.png" alt="" /&gt; &lt;/p&gt;  &lt;p&gt;tiene 5 proyectos:&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;AjCoreLisp&lt;/strong&gt;: la librería de clases, núcleo del proyecto, implementando el lenguaje base, pero sin parser ni lexer, sólo en runtime de ejecución.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;AjCoreLisp.Tests&lt;/strong&gt;: como es costumbre, desarrollé la librería anterior usando Test-Driven Development. Este es el proyecto de tests de la librería.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;MinimaLisp&lt;/strong&gt;: Una prueba de concepto. Tiene lexer, parser, y una mínima máquina que define el ambiente inicial. Muestra el uso de la librería núcleo, construyendo un intérprete Lisp mínimo.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;MiminaLisp.Console&lt;/strong&gt;: el intérprete de consola interactivo.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;MiminaLisp.Test&lt;/strong&gt;: Tests TDD escritos para el desarrollo de MinimaLisp.&lt;/p&gt;  &lt;p&gt;La interfaz raíz &lt;strong&gt;IExpression&lt;/strong&gt;:&lt;/p&gt;  &lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,courier,monospace;font-size:12px;"&gt;    &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;interface&lt;/span&gt; IExpression
    {
        &lt;span style="color:#0000ff;"&gt;object&lt;/span&gt; Evaluate(IEnvironment environment);
    }&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;Todo Lisp tiene soporte de lista. Esta es la &lt;strong&gt;IList&lt;/strong&gt; interfaz:&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,courier,monospace;font-size:12px;"&gt;    &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;interface&lt;/span&gt; IList : IExpression
    {
        &lt;span style="color:#0000ff;"&gt;object&lt;/span&gt; First { &lt;span style="color:#0000ff;"&gt;get&lt;/span&gt;; }
        &lt;span style="color:#0000ff;"&gt;object&lt;/span&gt; Rest { &lt;span style="color:#0000ff;"&gt;get&lt;/span&gt;; }
        IList Next { &lt;span style="color:#0000ff;"&gt;get&lt;/span&gt;; }
    }
&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;No actualización de los campos de la lista, es inmutable. Si queremos agregar que pueda cambiarse, hay que derivar de este proyecto, y poner la nueva implementación en un nuevo proyecto (como podría ser MinimaLisp u otro). Notar que tomado de Clojure la idea de tener Rest and Next: la primera retorna un objeto. Uso la segunda cuando espero que el resto de la lista sea una lista también.&lt;/p&gt;

&lt;p&gt;Todo form (cabeza ejecutable de lista) implementa &lt;strong&gt;IForm&lt;/strong&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,courier,monospace;font-size:12px;"&gt;    &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;interface&lt;/span&gt; IForm
    {
        &lt;span style="color:#0000ff;"&gt;object&lt;/span&gt; Apply(IEnvironment environment, IList arguments);
    }
&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;Entonces, la clase &lt;strong&gt;Form&lt;/strong&gt; implementa &lt;strong&gt;IForm&lt;/strong&gt; y &lt;strong&gt;IExpression&lt;/strong&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,courier,monospace;font-size:12px;"&gt;    &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;class&lt;/span&gt; Form : IForm, IExpression
    {
        &lt;span style="color:#0000ff;"&gt;private&lt;/span&gt; IList parameters;
        &lt;span style="color:#0000ff;"&gt;private&lt;/span&gt; IIdentifier parameter;
        &lt;span style="color:#0000ff;"&gt;private&lt;/span&gt; IList body;
        &lt;span style="color:#0000ff;"&gt;private&lt;/span&gt; IEnvironment environment;
        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; Form(IList parameters, IList body, IEnvironment environment)
        {
            &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.parameters = parameters;
            &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.body = body;
            &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.environment = environment;
        }
        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; Form(IIdentifier parameter, IList body, IEnvironment environment)
        {
            &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.parameter = parameter;
            &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.body = body;
            &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.environment = environment;
        }
&lt;span style="color:#008000;"&gt;// ....&lt;/span&gt;
        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;object&lt;/span&gt; Evaluate(IEnvironment environment)
        {
            &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;;
        }
        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;virtual&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;object&lt;/span&gt; Apply(IEnvironment environment, IList arguments)
        {
            IEnvironment newenv;
            
            &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (&lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.parameter != &lt;span style="color:#0000ff;"&gt;null&lt;/span&gt;)
                newenv = &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.MakeNewEnvironmentList(arguments);
            &lt;span style="color:#0000ff;"&gt;else&lt;/span&gt;
                newenv = &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.MakeNewEnvironment(arguments);
            &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; Machine.EvaluateBody(&lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.body, newenv);
        }
&lt;span style="color:#008000;"&gt;// ....&lt;/span&gt;
    }
&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;Noten que &lt;strong&gt;Form&lt;/strong&gt; no evalúa sus argumentos. Este es el trabajo de la clase derivada &lt;strong&gt;Function&lt;/strong&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,courier,monospace;font-size:12px;"&gt;    &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;class&lt;/span&gt; Function : Form, IExpression
    {
        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; Function(IList parameters, IList body, IEnvironment environment)
            : &lt;span style="color:#0000ff;"&gt;base&lt;/span&gt;(parameters, body, environment)
        {
        }
        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; Function(IIdentifier parameter, IList body, IEnvironment environment)
            : &lt;span style="color:#0000ff;"&gt;base&lt;/span&gt;(parameter, body, environment)
        {
        }
        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;override&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;object&lt;/span&gt; Apply(IEnvironment environment, IList arguments)
        {
            &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;base&lt;/span&gt;.Apply(environment, BaseForm.EvaluateList(arguments, environment));
        }
    }
&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;Como es usual, macros tienen una “vuelta de tuerca”: evalúan su cuerpo, pero entonces, evalúan el valor retornado:&lt;/p&gt;

&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,courier,monospace;font-size:12px;"&gt;    &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;class&lt;/span&gt; Macro : Form, IExpression
    {
&lt;span style="color:#008000;"&gt;// ...&lt;/span&gt;
        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;override&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;object&lt;/span&gt; Apply(IEnvironment environment, IList arguments)
        {
            &lt;span style="color:#0000ff;"&gt;object&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;value&lt;/span&gt; = &lt;span style="color:#0000ff;"&gt;base&lt;/span&gt;.Apply(environment, arguments);
            &lt;span style="color:#0000ff;"&gt;value&lt;/span&gt; = Machine.Resolve(&lt;span style="color:#0000ff;"&gt;value&lt;/span&gt;, environment);
            &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; Machine.Evaluate(&lt;span style="color:#0000ff;"&gt;value&lt;/span&gt;, environment);
        }
    }
&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;(Machine.Resolve está relacionado con una implementación de Delayed Evaluation, que uso para conseguir una especie de Tail Recursion). Ok, bastante código fuente por ahora. Miren el código del proyecto para más detalles. El punto principal es que &lt;strong&gt;AjCoreLisp&lt;/strong&gt; implementa pocas primitivas:&lt;/p&gt;

&lt;p&gt;&lt;img src="http://www.ajlopez.com/images/articles2/ajcorelisp02.png" alt="" /&gt; &lt;/p&gt;

&lt;p&gt;El enlace de primitivas al ambiente actual es el trabajo del MinimaLisp &lt;strong&gt;Machine:&lt;/strong&gt;&lt;/p&gt;

&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,courier,monospace;font-size:12px;"&gt;        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; MinimalMachine()
        {
            &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.Environment.SetValue(&amp;quot;&lt;span style="color:#8b0000;"&gt;first&lt;/span&gt;&amp;quot;, &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; First());
            &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.Environment.SetValue(&amp;quot;&lt;span style="color:#8b0000;"&gt;rest&lt;/span&gt;&amp;quot;, &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; Rest());
            &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.Environment.SetValue(&amp;quot;&lt;span style="color:#8b0000;"&gt;cons&lt;/span&gt;&amp;quot;, &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; Cons());
            &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.Environment.SetValue(&amp;quot;&lt;span style="color:#8b0000;"&gt;quote&lt;/span&gt;&amp;quot;, &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; Quote());
            &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.Environment.SetValue(&amp;quot;&lt;span style="color:#8b0000;"&gt;define&lt;/span&gt;&amp;quot;, &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; Define());
            &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.Environment.SetValue(&amp;quot;&lt;span style="color:#8b0000;"&gt;lambda&lt;/span&gt;&amp;quot;, &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; Lambda());
            &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.Environment.SetValue(&amp;quot;&lt;span style="color:#8b0000;"&gt;flambda&lt;/span&gt;&amp;quot;, &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; FormLambda());
            &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.Environment.SetValue(&amp;quot;&lt;span style="color:#8b0000;"&gt;mlambda&lt;/span&gt;&amp;quot;, &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; MacroLambda());
            &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.Environment.SetValue(&amp;quot;&lt;span style="color:#8b0000;"&gt;let&lt;/span&gt;&amp;quot;, &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; Let());
            &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.Environment.SetValue(&amp;quot;&lt;span style="color:#8b0000;"&gt;letrec&lt;/span&gt;&amp;quot;, &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; RecursiveLet());
            &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.Environment.SetValue(&amp;quot;&lt;span style="color:#8b0000;"&gt;eval&lt;/span&gt;&amp;quot;, &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; Evaluate());
            &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.Environment.SetValue(&amp;quot;&lt;span style="color:#8b0000;"&gt;if&lt;/span&gt;&amp;quot;, &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; If());
            &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.Environment.SetValue(&amp;quot;&lt;span style="color:#8b0000;"&gt;do&lt;/span&gt;&amp;quot;, &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; Do());
            &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.Environment.SetValue(&amp;quot;&lt;span style="color:#8b0000;"&gt;nil?&lt;/span&gt;&amp;quot;, &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; IsNil());
            &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.Environment.SetValue(&amp;quot;&lt;span style="color:#8b0000;"&gt;list?&lt;/span&gt;&amp;quot;, &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; IsList());
            &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.Environment.SetValue(&amp;quot;&lt;span style="color:#8b0000;"&gt;equal?&lt;/span&gt;&amp;quot;, &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; IsEqual());
        }
&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;Basado ese conjunto de primitivas, pude escribir más funciones:&lt;/p&gt;

&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,courier,monospace;font-size:12px;"&gt;(define list x x)
(define definem 
  (mlambda x 
    (list 
      &amp;#39;define 
      (first x)
      (cons &amp;#39;mlambda (rest x))
    )
  )
)
(define mapfirst (fn lst)
  (if (nil? lst)
    nil
    (cons 
      (fn (first lst)) 
      (mapfirst fn (rest lst))
    )
  )
)
    
(define mapcond (fn lst)
  (if (nil? lst)
    nil
    (if (fn (first lst))
      (cons 
        (first lst) 
        (mapcond fn (rest lst))
      )
      (mapcond fn (rest lst))
    )
  )
)
(define append (x y) (if (nil? x) y (cons (first x) (append (rest x) y))))
  
(definem cond lst
  (if (nil? lst)
    nil 
    (list 
      &amp;#39;if 
      (first (first lst)) 
      (cons &amp;#39;do (rest (first lst))) 
      (cons &amp;#39;cond (rest lst))
    )
  )
)
(define atom? (x)
  (cond 
    ((nil? x) t)
    ((list? x) nil)
    (t t)
  )
)
(definem and lst
  (if (nil? lst)
    t
    (list 
      &amp;#39;if 
      (first lst)
      (cons &amp;#39;and (rest lst))
      nil
    )
  )
)
(definem or lst
  (if (nil? lst)
    nil
    (list 
      &amp;#39;if 
      (first lst)
      t
      (cons &amp;#39;or (rest lst))
    )
  )
)
(define not (x)
  (if x
    nil
    t
  )
)
(definem backquote (lst) 
  (cond 
      ((nil? lst) nil)
        ((atom? lst) (list &amp;#39;quote lst))
        ((equal? (first lst) &amp;#39;unquote) (first (rest lst)))
        ((and (list? (first lst)) (equal? (first (first lst)) &amp;#39;unquote-slice)) (list &amp;#39;append (first (rest (first lst))) (list &amp;#39;backquote (rest lst))))
        (t (list &amp;#39;cons (list &amp;#39;backquote (first lst)) (list &amp;#39;backquote (rest lst))))
  )
)
(definem while lst
  (list &amp;#39;if (list &amp;#39;not (first lst)) nil (cons &amp;#39;do (rest lst)) (cons &amp;#39;while lst))
)&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;Me gusta mi implementación de &lt;strong&gt;backquote&lt;/strong&gt; (para usar en expansión de macros), un mini “tour-de-force” de este lenguaje. Estos tests dan verde (notar el uso de unquote y unquote-slice):&lt;/p&gt;

&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,courier,monospace;font-size:12px;"&gt;this.EvaluateAndCompare(&amp;quot;(backquote (a b c))&amp;quot;, &amp;quot;(a b c)&amp;quot;);
this.EvaluateAndCompare(&amp;quot;(backquote (a (b c) d))&amp;quot;, &amp;quot;(a (b c) d)&amp;quot;);
this.Evaluate(&amp;quot;(define x &amp;#39;(b b))&amp;quot;);
this.EvaluateAndCompare(&amp;quot;(backquote (a (unquote x) c))&amp;quot;, &amp;quot;(a (b b) c)&amp;quot;);
this.EvaluateAndCompare(&amp;quot;(backquote (a ((unquote x)) c))&amp;quot;, &amp;quot;(a ((b b)) c)&amp;quot;);
this.EvaluateAndCompare(&amp;quot;(backquote (a (unquote-slice x) c))&amp;quot;, &amp;quot;(a b b c)&amp;quot;);
this.EvaluateAndCompare(&amp;quot;(backquote (a ((unquote-slice x)) c))&amp;quot;, &amp;quot;(a (b b) c)&amp;quot;);
this.EvaluateAndCompare(&amp;quot;(backquote (a (unquote-slice x) (unquote-slice x) c))&amp;quot;, &amp;quot;(a b b b b c)&amp;quot;);
&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;No hay soporte de números. Escribí algunos tests usando implementaciones tipo Peano:&lt;/p&gt;

&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,courier,monospace;font-size:12px;"&gt;(define succ (x)
  (cons x nil))
  
(define pred (x)
  (first x))
(define add (x y)
  (if (nil? x)
    y
    (add (pred x) (succ y))
  )
)
&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;Hace un rato que no toco y mejoro el código, pero mi próximo paso podría ser refactorizar AjLisp (intérprete más completo) para basarse o tomar ideas de este intérprete núcleo. Ahora, tengo una idea más clara de lo que es necesario, esencial, y de lo que es accesorio en un intérprete Lisp.&lt;/p&gt;

&lt;p&gt;Y me divertí escribiendo esto &amp;quot;:-)&lt;/p&gt;

&lt;p&gt;Nos leemos!&lt;/p&gt;

&lt;p&gt;Angel “Java” Lopez 
  &lt;br /&gt;&lt;a href="http://www.ajlopez.com"&gt;http://www.ajlopez.com&lt;/a&gt; 

  &lt;br /&gt;&lt;a href="http://twitter.com/ajlopez"&gt;http://twitter.com/ajlopez&lt;/a&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1764833" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/lopez/archive/tags/.NET/default.aspx">.NET</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/C+Sharp/default.aspx">C Sharp</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/AjLisp/default.aspx">AjLisp</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/Lenguajes+de+Programaci_26002300_243_3B00_n/default.aspx">Lenguajes de Programaci&amp;#243;n</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/Programaci_26002300_243_3B00_n+Funcional/default.aspx">Programaci&amp;#243;n Funcional</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/AjCoreLisp/default.aspx">AjCoreLisp</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/Proyectos+de+C_F300_digo+Abierto/default.aspx">Proyectos de Código Abierto</category></item><item><title>AjIo: Intérprete tipo Io en C#</title><link>http://msmvps.com/blogs/lopez/archive/2010/05/01/ajio-int-233-rprete-tipo-io-en-c.aspx</link><pubDate>Sat, 01 May 2010 09:22:30 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1764655</guid><dc:creator>lopez</dc:creator><slash:comments>1</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/lopez/rsscomments.aspx?PostID=1764655</wfw:commentRss><comments>http://msmvps.com/blogs/lopez/archive/2010/05/01/ajio-int-233-rprete-tipo-io-en-c.aspx#comments</comments><description>&lt;p&gt;El año pasado, descubrí el lenguaje de programación Io:&lt;/p&gt;  &lt;p&gt;&lt;a title="http://www.iolanguage.com/" href="http://www.iolanguage.com/"&gt;http://www.iolanguage.com/&lt;/a&gt;&lt;/p&gt;  &lt;blockquote&gt;   &lt;h6&gt;overview&lt;/h6&gt;    &lt;p&gt;Io is a prototype-based programming language inspired by Smalltalk (all values are objects, all messages are dynamic), Self (prototype-based), NewtonScript (differential inheritance), Act1 (actors and futures for concurrency), LISP (code is a runtime inspectable/modifiable tree) and Lua (small, embeddable). &lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Tiene una sintaxis simple, sus características están basadas en lenguajes funcionales, Smalltalk, Self y otros. Como de costumbre, quiero escribir mi propia versión, con un cambio: soporte de objetos nativos. Esto es, para implementar un intérprete sobre una máquina virtual con librería de clases. Las actuales opciones son Java y .NET.&lt;/p&gt;  &lt;p&gt;Dos semanas atrás, el bueno de &lt;a href="http://twitter.com/MartinSalias" target="_blank"&gt;@MartinSalias&lt;/a&gt; me comentó sobre el lenguaje Io, y apareció de nuevo en mi radar. Entonces, el pasado domingo, comencé mi propia implementación, basado solamente en lo que leí en el sitio. No será el mismo lenguaje, veré que quedará o no adentro de esta implementación. Es trabajo en progreso.&lt;/p&gt;  &lt;p&gt;El código está en mi proyecto de Google AjCodeKata:&lt;/p&gt;  &lt;p&gt;&lt;a title="http://code.google.com/p/ajcodekatas/" href="http://code.google.com/p/ajcodekatas/"&gt;http://code.google.com/p/ajcodekatas/&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;En el trunk, en el directorio AjIo. Hay una solución .NET, con tres proyectos:&lt;/p&gt;  &lt;p&gt;&lt;img src="http://www.ajlopez.com/images/articles2/ajio06.png" alt="" /&gt; &lt;/p&gt;  &lt;p&gt;La librería de clases es el núcleo, el programa de consola puede ser usado para interactuar con el intérprete, y el proyecto de test tiene las pruebas automáticas que escribí durante el proceso de diseño/codificación.&lt;/p&gt;  &lt;p&gt;He escrito el lexer, el parser, y los principales objetos del lenguaje usando Test-Driven Development, como acostumbro.&lt;/p&gt;  &lt;p&gt;En una de las primeras pruebas del intérprete, podemos escribir:&lt;/p&gt;  &lt;p&gt;&lt;img src="http://www.ajlopez.com/images/articles2/ajio03.png" alt="" /&gt; &lt;/p&gt;  &lt;p&gt;Hace unos días, implementé los operadores de asignación ::=, :=, = (arreglos de sintaxis adornando los métodos setSlot, newSlot, updateSlot):&lt;/p&gt;  &lt;p&gt;&lt;img src="http://www.ajlopez.com/images/articles2/ajio04.png" alt="" /&gt; &lt;/p&gt;  &lt;p&gt;Un tiempo més tarde (pueden consultar el History.txt dentro del repositorio), agregué soporte de objectos nativos .NET:&lt;/p&gt;  &lt;p&gt;&lt;img src="http://www.ajlopez.com/images/articles2/ajio05.png" alt="" /&gt; &lt;/p&gt;  &lt;p&gt;Próximos pasos:&lt;/p&gt;  &lt;p&gt;- Escribir más operadores de comparación (sólo escribí ==)    &lt;br /&gt;- Números nativos (ahora, sólo son reconocidos por el lexer los enteros, pero pueden manejarse otros tipos, probar 1 / 6, retorna un double)     &lt;br /&gt;- Precedencia en operatdores aritméticos (ahora 2 + 2 * 3 retorna 12, en vez 8)     &lt;br /&gt;- for, foreach, range, y más (ahora hay sólo if())     &lt;br /&gt;- block() (Tengo implementado method())     &lt;br /&gt;- include()     &lt;br /&gt;- Comenzar a escribir parte de los objetos de la librería original de Io&lt;/p&gt;  &lt;p&gt;Sobre este últimos punto: debo decidir cóomo implemento cosas como:&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;List clone&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;Posibles opciones:&lt;/p&gt;  &lt;p&gt;- List como un objecto derivado de Object (obtenido de(Object clone) con sus propios slots, como wrapper sobre una lista nativa    &lt;br /&gt;- List clone retornando objectos ArrayList nativos, teniendo el tipo ArrayList sus slots asociados     &lt;br /&gt;- No implementar List, y usar directamente objetos nativos&lt;/p&gt;  &lt;p&gt;Como en &lt;a href="http://msmvps.com/blogs/lopez/archive/tags/AjSharp/default.aspx" target="_blank"&gt;AjSharp&lt;/a&gt;, el Io original tiene agentes y coroutines. Quiero agregar las características de AjSharp (agentes, goroutines, channels, queue channels, futures) en AjIo. Io implementa agentes en “threads” de máquina virtual: esto es, no usa los threads del sistema operativo, sino que la máquina virtual va ejecutando parte de un agente, parte del otro, pasado de un código a otro durante la ejecución&amp;#160; (eso es lo que imagino, no he visto el código de implementación). No tomaré esa aproximación, no por ahora. &lt;/p&gt;  &lt;p&gt;Este artículo, en Anglish:&lt;/p&gt;  &lt;p&gt;&lt;a title="http://ajlopez.wordpress.com/2010/04/30/working-in-ajio-io-like-interpreter-in-c/" href="http://ajlopez.wordpress.com/2010/04/30/working-in-ajio-io-like-interpreter-in-c/"&gt;http://ajlopez.wordpress.com/2010/04/30/working-in-ajio-io-like-interpreter-in-c/&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Como ven, me he divertido escribiendo todo esto!&lt;/p&gt;  &lt;p&gt;Nos leemos!&lt;/p&gt;  &lt;p&gt;Angel “Java” Lopez    &lt;br /&gt;&lt;a href="http://www.ajlopez.com"&gt;http://www.ajlopez.com&lt;/a&gt;     &lt;br /&gt;&lt;a href="http://twitter.com/ajlopez"&gt;http://twitter.com/ajlopez&lt;/a&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1764655" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/lopez/archive/tags/.NET/default.aspx">.NET</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/C+Sharp/default.aspx">C Sharp</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/Lenguajes+de+Programaci_26002300_243_3B00_n/default.aspx">Lenguajes de Programaci&amp;#243;n</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/Programaci_26002300_243_3B00_n+Funcional/default.aspx">Programaci&amp;#243;n Funcional</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/Proyectos+de+C_F300_digo+Abierto/default.aspx">Proyectos de Código Abierto</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/AjIo/default.aspx">AjIo</category></item></channel></rss>