Archive for the '12598' Category

La familia AjLisp: implementado intérpretes Lisp en C#

Tuesday, January 5th, 2010

En los últimos meses, estuve activo escribiendo intérpretes Lisp. Desde los ochenta, me gusta escribir ese tipo de intérpretes. Uno de mis ejercicios preferidos cuando estudio un nuevo lenguaje de programación, es escribir un intérprete Lisp en ese lenguaje (otro ejercicio es escribir un intérprete del lenguaje en estudio).

En el 2008, publiqué un código escrito en C#, AjLisp:

AjLisp: a Lisp interpreter in .NET
AjLisp: un intérprete Lisp en .NET

A la mitad del 2009, comencé a investigar Clojure. Dedicí explorar las nuevas ideas de ese lenguaje, reinplementánlo en C# (el Clojure original está escrito en Java, pero hay una versión en .NET, que compila usando DLR, Dynamic Language Runtime). Clojure compila a bytecodes Java. Mi versión es sólo un intérprete (debería estudiar y aprender sobre DLR o compilación .NET, y sobre cómo pasar el árbol de mi intérprete a código compilado). El resultado de todo esto es “work in progress”, se llama AjSharpure (se llamaba AjClojure, pero tuve que cambiar el nombre). Pueden ver el código, en desarrollo, en:

http://code.google.com/p/ajlisp/source/browse/#svn/trunk/AjSharpure

Inicialmente, mi idea era portar “uno a uno” el código de Java del Clojure original, pero me dí cuenta al tiempo que su código base no es fácilmente leíble, no tiene test en código, ninguna especificación acerca de la conducta esperada de docenas de clases y centeneares de métodos. Así que paré el desarrollo, y repensé el camino a seguir. Tomé coraje, olvidé el código inicial, y comencé de nuevo, de abajo hacia arriba, usando a fondo Test-Driven Development (TDD), implementando pieza por pieza, para ir consiguiendo parte por parte la conducta esperada externa del lenguaje, en vez de seguir de cerca su implementación interna.

Ahora está algo tranquilo el desarrollo de AjSharpure, porque estoy estudiando formas de implementar lo que me falta, como variables, Shared Transactional Memory, y otros temas, como References. Mientras, volví a mi versión 2008 de AjLisp. Escribí una nueva versión en 2009, haciendo un refactoring importante, armado de lo que había aprendido con AjSharpure. Ahora, tiene acceso y manejo de objetos y valores nativos. El trunk está en:

http://code.google.com/p/ajlisp/source/browse/#svn/trunk/AjLisp

No hay un Lisp “base”, y hay DOS principales dialectos: Common Lisp y Scheme. No me gustan algunas cosas de Common Lisp (debería escribir un post sobre mi razones), así, que para conocer más sobre Clojure y otros Lisp actuales, comencé a escribir AjScheme, un intérprete que implementa mucho de lo que es la referencia de Scheme (renuncié a implementar definición de macros como en el Scheme original, uso mis más conocidas mlambdas y expansión de macros):

http://code.google.com/p/ajlisp/source/browse/#svn/trunk/AjScheme

El AjLisp nació siguiendo un viejo libro de Christian Queinnec (un libro de los ochenta, no uno de sus más nuevos). No pude encontrar el código del libro en la web. Queinnec incluía en el texto el código de un intérprete Lisp escrito en su propio Lisp. No tengo el libro acá (lo tengo en mi segundo cubil). Me puse a investigar sobre lo mínimo que necesita ser implementado en un Lisp básico. Así que estos días estoy trabajando en el AjCoreLisp:

http://code.google.com/p/ajlisp/source/browse/#svn/trunk/AjCoreLisp

No tiene parser ni lexer. La idea es implementar un intérprete mínimo usando AjCoreLisp como la base: el resultado es MinimaLisp, y está incluido en ese trunk. Estoy implementando las mínimas primitvas, y estoy tratando de escribir el resto de las forms más comunes como funciones o macros. Una decisión “geek” 😉 : implementar la expasión de macros con backspace escribiéndola como una macro! El resultado en:

http://pastie.org/765371

Una vez que tenga AjCoreLisp/MinimaLisp estabilizado, haré refactor de AjLisp, AjScheme, para usar el kernel más pulido, pero agregaré como primitivas las forms más usadas. Debería medir el impacto de implementar forms más usadas como macros, en lugar de primitivas. Tengo confianza en poder hacer todos esos cambios, porque todo lo escrito está vigilado por una batería de tests (el haber seguido TDD y tener tests me ha salvado el día muchas veces, cuando he refactorizado mucho del código base).

Como próxima misión: escribir posts sobre estos diferentes intérpretes, variaciones sobre un leit-motiv: las hermosas ideas del lenguaje Lisp.

Para los que quieran estudiar más sobre Lisp, mis enlaces sobre el tema:

http://delicious.com/ajlopez/lisp
http://delicious.com/ajlopez/scheme
http://delicious.com/ajlopez/clojure
http://delicious.com/ajlopez/commonlisp

Nos leemos!

Angel “Java” Lopez
http://www.ajlopez.com
http://twitter.com/ajlopez