Proyecto Liqueed (1)

Hoy quería presentar en un post corto, al proyecto Liqueed, pueden ver el repo en:

https://github.com/liquid-co-ops/liqueed

desarrollado como aplicación web sobre una idea del bueno de @acyment, leer su post (en inglés):

http://blog.agilar.org/index.php/2014/04/30/leancoops-first-draft/

La idea básica de la aplicación es ayudar a los equipos que estén desarrollando algo a la manera que sugiere Cyment en el tema del reparto de acciones sobre el proyecto. Desde hace unos meses, la aplicación (el código, el backlog, las ideas, la implementación, el hosting y demás) se viene armando en un equipo que también quiere ser “líquido” (con entrada y salida de gente, pero aún estamos cortos con el tema de las votaciones propias, en casa de herrero :-)

En esta serie de posts que hoy inicio, quisiera comentar temas técnicos interesantes que plantea el proyecto. Por hoy, comento que:

- Es una aplicación Node.js, expuesta a la web usando Express. Con lo que el lenguaje de programación es JavaScript.

- Además de algunas páginas internas de administración con MVC, tiene una API expuesta, que intercambia JSON.

‘- Hay una aplicación Single Page que es la que tendría que usar el usuario final, para ver los proyectos, las votaciones, los repartos de acciones y para ingresar las nuevas votaciones

- La mayor parte del código fue escrito usando el flujo de trabajo de TDD (Test-Driven Development). Incluso, el primer código implementó el modelo en memoria, permitiendo avanzar más fácil sobre la implementación de casos de uso, sin tener que detenerse tanto en la persistencia (hasta el cliente SPA puede ejecutarse sin necesidad de tener un servidor andando)

- Hace ya unos meses, agregamos persistencia con MongoDB. Podríamos usar otra base, relacional quizás. No estamos aprovechando las facilidades de manejar documentos de MongoDB todavía. Solamente la elegimos por su ubicuidad en las plataformas de desarrollo y en los distintos servicios de hosting de Node.

- En algún momento agregamos Istambul para el cubrimiento de código.

- Cuando los tests de TDD por código puro comenzaron a ser largos, se agregó un DSL (Domain Specific Language) simple que permite escribir archivos de texto con los pasos a seguir en el test funcional

- Comenzamos a agregar tests de la SPA (Single Page Application) usando Zombie

Y habría mucho más para comentar, espero que con más detalle en los próximos posts.

Nos leemos!

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

Posted in Desarrollo Agil, Desarrollo Web, JavaScript, Liqueed, MongoDB, NodeJs, Proyectos Open Source | Comments Off

JavaScript e Inteligencia Artificial (3)

Anterior Post

Un tema que presenté con un ejemplo (pero sin ejecutarlo) es la evaluación de la próxima jugada en un juego de tablero. No pude dejar de mencionar a una película que vi hace décadas y que me influyó bastante en la forma de ver la inteligencia artificial, Juegos de Guerra (“War Games” de 1983, ver Wikipedia ver IMDB):

En los juegos de tablero, es común evaluar una posición, y dada las posibles jugadas, evaluar las posiciones resultantes, eligiendo la mejor para nuestro bando. El problema es determinar cuál es “la mejor”. En general, no hay funciones de evaluación perfecta de una posición. Lo que se puede hacer, es explorar un árbol de jugadas, para tener una evaluación “más profunda” de la posición actual. Esto permite calcular un valor de la posición actual en base a la posible evolución de las próximas jugadas. Hay varias formas de explorar un árbol (los remito al libro mencionado en el anterior post, base de toda la charla)

Elegí como ejemplo, un juego de tablero con azar, donde las jugadas son azarozas (hay un tiro de dados), el conocido backgammon. Lo elegí con cierta nostalgia del trabajo de Hans Berliner, en los ochenta, que conocí gracias a un artículo del Scientific American:

 

Fue el primer programa que le ganó a un campeón mundial humano en un juego de tablero. Pueden leer los artículos de Hans Berliner en:

Backgammon Computer Program Beats World Champion
Computer Backgammon

Si leen la descripción del programa, tiene mucha heurística, mucho conocimiento experto del juego. Mi proyecto es más modesto y trata de que la evaluación de una posición “emerga” de explorar el árbol de jugadas, calculando al final una “métrica” sencilla de cuán lejos estamos del objetivo final (sacar todas las fichas del tablero antes que el adversario).

El proyecto en JavaScript en:

https://github.com/ajlopez/SimpleGammon

Escrito usando TDD (Test-Driven Development) desde Node.js consola. Pero el ejemplo es para browser:

https://github.com/ajlopez/SimpleGammon/tree/master/samples/html

Tiene una interfaz simple, a mejorar:

Ejecuta la evaluación de dos jugadas hacia adelante, en el cliente. Antes de “Play” pueden elegir quien mueve, y cuales son los dados iniciales. Pero vean que tarda sus buenos segundos, un tema a mejorar. Varias opciones a explorar, como procesamiento en paralelo (vimos en la conferencia que JavaScript tiene implementaciones para aprovechar procesadores), y también, derivar la evaluación al servidor, y que éste lo derive a varias máquinas “worker” (algo así hice para otro ejemplo, de algoritmos genéticos).

Otros proyectos en los que estoy trabajando para evaluar posiciones (pero todavía sin ejemplos, trabajo en progreso):

https://github.com/ajlopez/SimpleGo
https://github.com/ajlopez/SimpleChess

El juego del Go es atrapante, pero no trivial. Primero, quiero avanzar más con la implementación de backgammon, el primer candidato es evaluación distribuida.

Nos leemos!

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

Posted in Charlas, Inteligencia Artificial, JavaScript, NodeJs, Proyectos Open Source | Comments Off

Resoluciones del Nuevo Mes: Enero 2015

Un nuevo año comienza. Pero para mí, sigue siendo el mes la unidad de “nuevas resoluciones”: me parece así que es más útil, flexible y alcanzable. Tiempo de revisar las resoluciones del mes pasado,  y plantear las nuevas:

- Agregar características distribuidas a AjErl, el intérprete tipo Erlang en C# [parcial] ver repo
- Mejorar ClojSharp [completo] ver repo
- Mejorar SimpleLisp [completo] ver repo
- Generación de Código con AjGenesis para Node [pendiente]
- Comenzar Basic Script Language en C# [completo] ver repo

Adicionalmente, estuve trabajando en:

- Mejorar ScalaSharp [completo] ver repo
- Primeras operaciones del emulador Chip8 en JavaScript [completo] ver repo
- Escribir ejemplos de Clojure (con Ring, Compojure) [completo] ver repo
- Trabajar en proyecto Liqueed [completo] ver repo
- Mejorar AjScript [completo] ver repo

Las resoluciones para el nuevo mes:

- Continuar con características distribuidas de AjErl, intérprete tipo Erlang en C#
- Mejorar ClojSharp
- Mejorar ScalaSharp
- Mejorar emulador Chip8 en JavaScript
- Generar código con AjGenesis para Node
- Mejorar Basic Script Language para C#
- Escribir posts de JavaScript e Inteligencia Artificial

Nos leemos!

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

Posted in .NET, AjErl, AjScript, C#, ClojSharp, JavaScript, NodeJs, Proyectos Open Source, Simpl, SimpleLisp | Leave a comment

Aktores Implementando Akka Actor Model en C# (2) Un simple Ejemplo

Anterior Post

Veamos hoy un simple ejemplo que crea dos actores y les envía mensaje. El código completo está en:

https://github.com/ajlopez/Aktores/tree/master/Samples/PingPong

Como siempre, todo es “trabajo en progreso”, y puede cambiar en el futuro. Estoy siguiendo el flujo de trabajo de TDD (Test-Driven Development), así que alguna llamada a la API puede ir cambiado, o cambiar algún concepto de base, a medida que me planteo casos de uso cada vez más interesantes (ya llegué a implementar caso de uso distribuido, por ejemplo).

En este ejemplo, tenemos un actor:

using Aktores.Core;

public class PingActor : Actor
{
    private int messagecount;

    public int MessageCount { get { return this.messagecount; } }

    public override void Receive(object message)
    {
        messagecount++;
        this.Sender.Tell("ping", this.Self);
    }
}

Vean que un actor desciende de una clase base Actor. El gran método a implementar es el Receive, que recibe un mensaje enviado por alguien en el sistema (otro actor, otro objeto) a nuestra instancia. Aktores se asegura que los mensajes nos lleguen y se procesen de a uno por vez. En el actor de arriba, una vez recibido un mensaje, incrementa un contador y le responde al enviador del mensaje original con otro mensaje (el enviador está referenciado en this.Self, DURANTE el proceso de un mensaje; luego puede cambiar al llegar otro mensaje).

Otro actor similar:

using Aktores.Core;

public class PongActor : Actor
{
    private int messagecount;

    public int MessageCount { get { return this.messagecount; } }

    public override void Receive(object message)
    {
        messagecount++;
        this.Sender.Tell("pong", this.Self);
    }
}

El programa principal, lo que hace, es crear un sistema de actores, crear dos actores, uno del tipo Ping y otro del tipo Pong, y luego le envía mensajes a procesar:

public static void Main(string[] args)
{
    ActorSystem system = new ActorSystem(2);
    var pingactor = new PingActor();
    var pongactor = new PongActor();
    
    var ping = system.ActorOf(pingactor);
    var pong = system.ActorOf(pongactor);

    for (int k = 0; k < 10; k++)
    {
        ping.Tell("pong", pong);
        pong.Tell("ping", ping);
    }

    // ....
}

Tiene código adicional para medir la cantidad de mensajes que se procesan en el tiempo. El parámetro 2 en el constructor de ActorSystem indica que necesita DOS threads de trabajo interno para procesar mensajes. Deberé revisar si esa información queda ahí o de otra manera. Dos threads son suficientes porque no tenemos más que dos instancias de actores, pero podríamos poner otro número si usamos más actores.

Nos leemos!

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

Posted in .NET, Actor Model, Aktores, C, C#, Proyectos Open Source | Comments Off

SimpleLisp (2) Compilando Valores y Variables Lisp a JavaScript

Anterior Post

Veamos algo de la implementación del proyecto

https://github.com/ajlopez/SimpleLisp

el compilador de Lisp a JavaScript, escrito en JavaScript, siguiendo el flujo de trabajo de TDD (Test-Driven Development). Todo es “trabajo en progreso” así que lo explico hoy es la implementación actual, de este día, que puede ir cambiando a medida que se vayan implementando nuevos casos de uso.

Tomé la decisión de que cada símbolo de Lisp sea una variable de JavaScript. Así que la compilación de un símbolo queda expresada en este test:

exports['compile symbol'] = function (test) {
    test.equal(sl.compile('a'), 'a');
}

El sl es módulo SimpleLisp que ya tengo cargado con require, al principio de los tests. Este test de arriba lo tomé de test/compile.js

Un entero y un string se compilan a valores naturales en JavaScript:

exports['compile integer'] = function (test) {
    test.equal(sl.compile('42'), '42');
}

exports['compile string'] = function (test) {
    test.equal(sl.compile('"foo"'), '"foo"');
}

También se compilan a valores naturales sus valores “quoted”:

exports['compile quoted integer'] = function (test) {
    test.equal(sl.compile("'42"), '42');
}

exports['compile quoted string'] = function (test) {
    test.equal(sl.compile("'\"foo\""), '"foo"');
}

Decidí tratar a nil como el null de JavaScript. Los valores booleanos se compilan tal cual:

exports['compile nil'] = function (test) {
    test.equal(sl.compile('nil'), 'null');
}

exports['compile booleans'] = function (test) {
    test.strictEqual(sl.compile('false'), 'false');
    test.strictEqual(sl.compile('true'), 'true');
}

¿Pero qué pasa si hay que compilar una serie de expresiones Lisp? Armo una función anónima, la invoco sin parámetros, y devuelvo el valor de la última expresión:

exports['compile two symbols'] = function (test) {
    test.equal(sl.compile('a b'), '(function () { a; return b; })()');
}

Próximos temas: compilación de una lista y de valores quoted más complejos.

Nos leemos!

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

Posted in JavaScript, Lisp, NodeJs, Proyectos Open Source, SimpleLisp, Te, Test-Driven Development | Comments Off

Resoluciones del Nuevo Mes: Diciembre 2014

Es tiempo de revisar las resoluciones del mes pasado:

- Dar una charla sobre JavaScript e Inteligencia Artificial [completo] ver repo ver presentación leer post
- Ejemplo de Red Neuronal en JavaScript [completo] ver repo
- Ejemplos de Algoritmos Genéticos en JavaScript [completo] ver repo
- Más Generación de Código con AjGenesis para Node.js [pendiente]
- Basic Script Language para C# [pendiente]
- Mejorar SimpleScript para JavaScript [completo] ver repo

También estuve trabajando en:

- Mejorar SimpleLisp, compilador Lisp a JavaScript [completo] ver repo
- Mejorar RuScript, intérprete Ruby en JavaScript [completo] ver repo
- Mejorar RustScript, intérprete Rust (no tipado) en JavaScript [completo] ver repo
- Crear SimpleDT, un simple árbol de decisión en JavaScript [completo] ver repo
- Mejorar ClojSharp, un intérprete Clojure en C# [completo] ver repo
- Evaluación de Backgammon en página HTML [completo] ver repo

Las resoluciones para este nuevo mes de Diciembre:

- Agregar características distribuidas a AjElr, un Erlang interpretado en C#
- Mejorar ClojSharp, un Clojure en C#
- Mejorar SimpleLisp, compilador de Lisp a JavaScript, escrito en JavaScript
- Generación de código con with AjGenesis para Node
- Comezar Basic Script Language en C#

Nos leemos!

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

Posted in .NET, C#, JavaScript, NodeJs, Proyectos Open Source | Leave a comment

JavaScript e Inteligencia Artificial (2)

Anterior Post
Siguiente Post

Gracias a la gente de JSConf Argentina 2014 por haberme dado la oportunidad de dar esta charla, ayer, en esa excelente conferencia. Para darle un formato dinámico, las charlas fueron de veinte minutos. Quisiera en esta serie de posts completar la exposición de lo que quería mostrar, comentando más en detalle algunos puntos, y presentando también otras demos y proyectos que quedaron fuera de la charla.

El tema de hoy es recomendarles EL libro que me sirvió de guía de estudio para un tema interminable, un clásico de la ciencia de la computación (el cuarto más citado en este siglo):

Artificial Intelligence, a Modern Approach
http://aima.cs.berkeley.edu/

de Stuart Russell y Peter Norvig. Para saber más sobre la tapa de la última edición, ver:

http://aima.cs.berkeley.edu/cover.html

Hay alguna edición en español, y yo la habré conseguido en las librerías de Buenos Aires, ya hace unos años. Son algo más de mil páginas, en veintisiete capítulos y apéndices, donde se visita desde agentes inteligentes hasta redes neuronales, desde algoritmos de búsqueda y evaluación de árboles hasta robótica y temas filosóficos. Me parece muy interesante que cada capítulo esté acompañado de notas sobre la historia del tema, lo que siempre pienso que nos da perspectiva y mejor comprensión sobre los problemas y dificultades en un desarrollo. No hay que quedarse solamente con “lo que se sabe ahora”, sino también estudiar cuál fue el camino seguido para llegar al estado actual, lo que también puede servir para entender cuál es el futuro que podemos seguir.

Tienen el seudocódigo de los ejemplos en http://aima.cs.berkeley.edu/algorithms.pdf  y también en código Lisp, Python, Java en http://aima.cs.berkeley.edu/code.html

Es interminable también para investigar: AI on the web http://aima.cs.berkeley.edu/ai.html

En la edición que tengo, no aparece JavaScript como lenguaje de programación a usar. Es un buen ejercicio ir adaptando los ejemplos en seudocódigo a implementaciones en distintos lenguajes. Cada tanto, trato de implementar algo en el proyecto https://github.com/ajlopez/NodeAima. Notablemente, JavaScript debe ser el lenguaje más simple para implementar muchas de las ideas del libro. Implementaciones en lenguajes tipados y no dinámicos, como Java y C#, me parecen que tienen siempre algo de “convoluted” comparando con una implementación directa en JavaScript. Ver por ejemplo https://github.com/ajlopez/SharpAima

Nos leemos!

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

Posted in Charlas, Inteligencia Artificial, JavaScript, NodeJs | Comments Off

JavaScript e Inteligencia Artificial (1)

Siguiente Post

Gracias a la gente de JSConf Argentina 2014, hoy voy a estar dando una charla corta sobre JavaScript e Inteligencia Artificial. La idea es presentar rápidamente algunas ideas, algoritmos, demo de implementaciones, y cerrar con comentarios sobre lo que parece interesante seguir. Inteligencia Artificial es un término muy amplio, y que nació hace décadas. Desde entonces, ha ido acumulando definiciones, ambiciones, herramientas y aproximaciones a tratar de construir agentes inteligentes.

El repositorio de la charla en:

https://github.com/ajlopez/JavaScriptAI

donde hay enlaces a los proyectos presentados, demos, y recursos adicionales.

Los “fuentes” de la presentación de la charla en:

https://github.com/ajlopez/Talks/tree/master/JavaScriptAI

La presentación en línea en:

http://ajlopez.github.io/Talks/JavaScriptAI/index.html#/
http://ajlopez.github.io/Talks/

En la charla visito dos grandes temas: algoritmos genéticos, y redes neuronales. También hay un corto tiempo dedicado a explorar un árbol de juego de tablero. Y hay una demo de algoritmo genético aplicado a programación evolutiva. Quedó fuera de la charla el tema de crear árboles de decisiones, basados en datos. Pero ya lo voy a comentar en los próximos posts las ideas, demos y recursos que me interesaron, y los proyectos que estuve escribiendo.

Nos leemos!

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

Posted in Algoritmos Genéticos, Charlas, Inteligencia Artificial, JavaScript, NodeJs, Proyectos Open Source, Redes Neuronales | Comments Off

SimpleScript (3) El Parser, Expresiones y Comandos

Anterior Post

Veamos hoy parte del Parser, que es un módulo separado. Comienza con una declaración sencilla:

'use strict';

var lexer;

if (typeof lexer == 'undefined')
    lexer = require('./lexer');

var parser = (function () {
    var TokenType = lexer.TokenType;
    var binoperators = [ "+", "-", "*", "/", "==", "!=", "<", ">", "<=", ">=" ];

Usa a lexer, y lo requiere. Luego hay definidos expresiones y comandos. Por ejemplo, esta es la expresión para un simple nombre (por ejemplo, foo):

function NameExpression(name) {
    this.isLeftValue = true;

    this.compile = function () {
        return name;
    };

    this.getName = function () {
        return name;
    }

    this.collectContext = function (context) {
        context.declare(name);
    }
}

Veremos en el próximo post cómo se detecta y construye esta expresión. Una expresión cualquiera tiene que implementar por lo menos dos métodos: compile, que devuelve la expresión compilada a un string de código JavaScript, y collectContext, que permite descubrir las variables declaradas en un programa. En este caso, la NameExpression declara a su nombre (por ejemplo, “foo”), como una variable declarada en el programa (esto es necesario para tener implementado el “hoisting” como en JavaScript).

Veamos una IndexedExpression: compuesta de una expresión y otra expresión para el índice (representaría expresiones como foo[42+1]):

function IndexedExpression(expr, indexpr) {
    this.isLeftValue = true;

    this.compile = function () {
        return expr.compile() + '[' + indexpr.compile() + ']';
    };

    this.collectContext = function (context) {
        expr.collectContext(context);
    }
}

Vean como ahora el collectContext se toma el trabajo de visitar la expresión interna (no vi que fuera necesario visitar y descubrir variables en la expresión de índice, pero puede que lo agregue; esa expresión en general es simple, pero bien podría tener usada una variable).

Pero también hay comandos. Puedo poner como ejemplo el IfCommand:

function IfCommand(cond, thencmd, elsecmd) {
    this.compile = function () {
        var code = 'if (' + cond.compile() + ') { ' + thencmd.compile() + ' }';
        if (elsecmd)
            code += ' else { ' + elsecmd.compile() + ' }';
        return code;
    };

    this.collectContext = function (context) {
        cond.collectContext(context);
        thencmd.collectContext(context);
        if (elsecmd)
            elsecmd.collectContext(context);
    }
}

La distinción entre comandos y expresiones es por ahora puramente formal. Vean que este comando tiene que implementar cómo se compila a JavaScript un if, dado la cond (expresión de la condición), el thencmd (el comando de la rama then), y el elsecmd (el comando de la rama else, que es opcional). Y el collectContext deriva a esas subpartes.

Como siempre, desarrollo paso a paso, usando el flujo de trabajo de TDD (Test-Driven Development). Ejemplo parcial:

exports['Compile string without quotes inside'] = function (test) {
    test.equal(compileExpression("'foo'", test), "'foo'");
    test.equal(compileExpression('"foo"', test), "'foo'");
}

exports['Compile name'] = function (test) {
    test.equal(compileExpression("foo", test), "foo");
}

exports['Qualified name'] = function (test) {
    test.equal(compileExpression("foo.bar", test), "foo.bar");
}

exports['Indexed term'] = function (test) {
    test.equal(compileExpression("foo[bar]", test), "foo[bar]");
}

Ya saben ;-) Sin TDD no hay paraíso!

Próximos temas: cómo se reconocen las expresiones y comandos.

Nos leemos!

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

Posted in JavaScript, NodeJs, Proyectos Open Source, SimpleScript, Test-Driven Development | Comments Off

SimpleLisp (1) Compilando Lisp a JavaScript

Siguiente Post

Ya varias veces implementé un intérprete Lisp, en C#, en Java, en JavaScript. Ver proyectos

https://github.com/ajlopez/AjLisp
https://github.com/ajlopez/AjLispJava
https://github.com/ajlopez/AjLispJs

Siempre es bueno implementar Lisp. Es un lenguaje simple, sencillo, poderoso, con funciones como ciudadanos de primera clase, y con el “twist” de implementar: algunas funciones que no evalúan de antemano sus argumentos, y macros.

Pero esta vez quiero implementar un compiladr Lisp. Es decir, algo que traslade al lenguaje anfitrión el programa Lisp. He elegido JavaScript como lenguaje anfitrión, y también como lenguaje de compilación: JavaScript mismo es el encargado de leer y traducir código Lisp a JavaScript. Pueden ver mi avance en

https://github.com/ajlopez/SimpleLisp

Como es costumbre, todo armado siguiendo el flujo de trabajo de TDD (Test-Driven Development), y sin tener todo el diseño de antemano, simplemente va surgiendo con los pequeños casos de uso que voy incorporando. Como es mi primer compilador Lisp, estoy aprendiendo nuevas formas de implementar el lenguaje. Algo vi en los últimos años al toparme con Clojure, que compila a Java, a CLR y a JavaScript. Lo que veo que tengo que implementar es:

Símbolos: identificadores por nombre, con valor asociado. Los estoy compilando a variables de JavaScript. En SimpleLisp, un símbolo puede quedar definido para el tope del programa, para un bloque let, o como argumento de una función. Entonces, depende del caso, lo paso a una variable tope de JavaScript (o al menos, tope en el módulo que estoy armando en compilación), a una variable local, o a un argumento con nombre.

Funciones: traducir una función normal de Lisp a una función normal de JavaScript. Lo único diferente es que las funciones de Lisp siempre devuelven en un valor, los “comandos” son siempre expresiones, como en Ruby. Una lista a evaluar en SimpleLisp la compilo a una llamada a función simple en JavaScript.

Special Forms: Su implementación es novedosa para mí. Ahora que tengo que compilar, no interpretar, cada vez que me topo con un una lista cuya cabeza es un if, un do, un let, etc…  voy y la compilo de forma especial a JavaScript. Un (if … ) de SimpleLisp queda transformado en un if de JavaScript (es un poco más complicado, porque el if de SimpleLisp tiene que devolver un valor, es una expresión, mientras que un if de JavaScript es un comando; ya veremos en futuro post la implementación que adopté).

Macros: De nuevo, al tener que compilar, puedo adoptar una implementación nueva: expandir la macro AL MOMENTO DE COMPILAR. Veremos hasta donde puedo llegar con este camino. Una consecuencia que veo: no puedo pasar una macro como valor funcional como argumento de otra función. Justamente, lo que pasa en Clojure: las macros no son valores funcionales, son “trucos” que se expande en tiempo de compilación.

Y como en otras implementaciones, agrego acceso a invocar JavaScript nativo desde SimpleLisp. Mi idea es poder escribir un sitio Node.js/Express con SimpleLisp.

Nos leemos!

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

Posted in JavaScript, Lenguajes de Programación, Lisp, NodeJs, Proyectos Open Source, SimpleLisp, Test-Driven Development | Comments Off