Archive for the '8313' Category

Resoluciones del Nuevo Mes: Abril 2014

Sunday, April 6th, 2014

Llega revisión de mis resoluciones de marzo:

– Trabajar en DictSharp [completo] ver repo
– Dar una charala sobre Aplicaciones Distribuidas en Node.js [completo] ver repo ver presentación
– Mejorar SimpleGammon [completo] ver repo
– Mejorar Annalisa [completo] ver repo
– Agregar @for a Templie [pendiente]
– Trabajar en PreciosaAnnalisa online web services [completo] ver repo
– Mejorar mis ejemplos de Aplicaciones Distribuidas en Node.js [completo] ver repo ver repo ver repo
– Trabajar en ScalaSharp [completo] ver repo
– Mejorar ClojSharp [completo] ver repo
– Mejorar SimpleAsync, operación do (funciones en “paralelo”) [pendiente]
– Mejorar Aktores [pendiente]
– Mensajes distribuidos en AjErl [pendiente]
– Agregar alcance de variables al lenguaje Mass [pendiente]
– Comenzar a codificar generation as a service [parcial]

Adicionalmente, estuve trabajando en:

– Complexo, operaciones de números complejos en JavaScript [completo] ver repo
– Comenzar RustScript, un intérprete de Rust en JavaScript [completo] ver repo
– Continuar RuScript, intérprete de Ruby en JavaScript [completo] ver repo
– Continuar RubySharp, intérprete de Ruby en C# [completo] ver repo
– Comenzar AjLispScala, intérprete Lisp en Scala, usando TDD y SBT [completo] ver repo
– Grabar un segundo video de aprendiendo Node.js [completo] ver post

Para este nuevo mes, mis resoluciones son:

– Continuar AjLispScala
– Continuar AjGenesisNode-Express
– Continuar AjGenesisNode-PHP
– Continuar RuScript
– Continuar RustScript
– Mensajes distribuidos en AjErl
– Dar una charla de introducción a Node.js
– Publicar un nuevo video de Aprendiendo Node.js

Nos leemos!

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

Resoluciones del Nuevo Mes: Febrero 2014

Saturday, February 8th, 2014

Revisión de mis Resoluciones de Enero:

– Comenzar a implementar un modelo de actores a la Akka en C# [completo] ver repo
– Comenzar a implementar un intérprete Scala en JavaScript [completo] ver repo
– Trabajar en AjErl, Erlang en C# [completo] ver repo
– Trabajar en Mass (tengo varias ideas para implementar más module pattern y scope de variables) [pendiente]
– Trabajar en DylanSharp [completo] ver repo
– Comenzar una implementacion de ML (JavaScript? C#?) [pendiente]

También trabajé en:

– Mejorar intérprete Scala en C# [completo] ver repo
– Agregar notación dot en mi intérprete Lisp en C# [completo] ver repo
– Mejorar el intérprete Ruby en JavaScript [completo] ver repo
– Mejorar el intérprete Clojure en C# [completo] ver repo
– Primeros templates y tasks generando código Sinatra desde AjGenesis para Node [completo] ver repo

Mis resoluciones para este nuevo mes:

– Completar mensajería distribuida en AjErl
– Completar notación dot en AjLisp para acceder a tipos y objetos nativos
– Mejorar ClojSharp
– Trabajar en ScaScript
– Trabajar en ScalaSharp
– Agregar alcance de variables a Mass
– Completar primera versión de model de actores Aktores en C#
– Más tareas de generación de código, plantillas, modelos en AjGenesis para Node, generando código para Express, Meteor, Sinatra

Nos leemos!

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

Implementando Lenguajes de Programación en Javascript, JsConf Argentina

Monday, May 21st, 2012

Ayer, 20 de Mayo, tuve el gran gusto de presentar un tema que me gusta mucho, la implementación de lenguajes de programación, y en este caso, usando Javascript como lenguaje destino. Fue en la JSConf Argentina 2012:

http://jsconf.com.ar/

(Ya había escrito un post anunciando la conferencia) El día fue excelente, llena de interesantes charlas, muy bien organizada por @rauchg y su equipo (creo de @vulsai), tomé muchas notas, espero escribir uno o dos posts sobre el tema, en cuanto me recupere 😉 Mientras, pueden leer el post de @aijoona

http://blog.aijoona.com/2012/05/21/jsconf-ar-2012-mi-resumen/

Como ejemplo de charla, vean la de WebGL para javascripters de @gerbille:

http://www.slideshare.net/gerbille/webgl-para-javascripters

Este post contiene los enlaces y las implementaciones que visité y preparé para la charla, que tuvo poco de gráfico, y mucho, mucho de código. Debería comenzar a usar los lenguajes que presenté, para manejar temas gráficos en el cliente, por ejemplo WebGL, SVG, tal vez usar d3.js.

Mi presentación en mi Skydrive (nota: tengo que escribir la próxima presentación mía, supongo que será en el Ruby Meetup, en markdown y publicarla en HTML).

Lista de lenguajes que compilan a Javascript
https://github.com/jashkenas/coffee-script/wiki/List-of-languages-that-compile-to-JS

The JavaScript World Domination Plan at 16 Years
http://www.infoq.com/presentations/The-JavaScript-World-Domination-Plan-at-16-Years

Lisp as the Maxwell’s equations of software
http://www.michaelnielsen.org/ddi/lisp-as-the-maxwells-equations-of-software/

A Conversation with Alan Kay
http://queue.acm.org/detail.cfm?id=1039523

The Magnificent Seven
by Michael Fogus
http://fogus.me/static/preso/magnificent7/#slide1

McCarthy’s Lisp in Python with macros
https://github.com/fogus/lithp

The roots of Lisp
http://www.paulgraham.com/rootsoflisp.html

Presenté AjLisp en Javascript
https://github.com/ajlopez/AjLispJs

Comenté y mostré demo de AjLogo en Javascript
https://github.com/ajlopez/AjLogoJs
Demo http://ajlopez.github.com/AjLogoJs/demo.html

Otras implementaciones de Logo en Javascript
http://www.calormen.com/Logo/
http://logo.twentygototen.org/

Recomendé ver a NetLogo http://ccl.northwestern.edu/netlogo/ (en Java) para ver hasta dónde ha llegado el tema.

Hice correr el REPL y el compilador de Clojurescript
https://github.com/clojure/clojurescript

Presenté a la AjTalk VM en C#, y desde el año pasado compila Smalltalk a Javascript
https://github.com/ajlopez/AjTalk

Este año agregué AjTalk en Javascript, con VM en bytecodes, y ejecutor de métodos compilados con AjTalk
https://github.com/ajlopez/AjTalkJs
Demo http://ajlopez.github.com/AjTalkJs/demo.html

Mostré una simple demo de clases Smalltalk compiladas a Javascript, que manejan google, y google.earth.

Levanté Amber y comenté cómo en su definición de métodos ponen Javascript nativo
http://amber-lang.net/

Visité la página de Smalltalk S8, U8
http://u8.smalltalking.net/
http://u8.smalltalking.net/browsecontributions.aspx

No pudimos ver las demos, justo en ese momento estuve sin conexión. Les comento algunos enlaces. Veamos dos:

Hay una Smalltalk S8 Console (con una compilación de V8 preparada para levantar código st)
http://u8.smalltalking.net/profile/smalltalking/125/index.html

Ver sus demos de Google Earth
http://u8.smalltalking.net/contribution.aspx?contributionId=222
(exploren las clases, creo que eran Google, GoogleEarth, GoogleEarthObject, GEDemo, etc…)

Mis posts sobre AjTalk, AjLisp, AjLogo implementations
http://ajlopez.wordpress.com/category/ajtalk/
http://ajlopez.wordpress.com/category/ajlisp/
http://ajlopez.wordpress.com/category/ajlogo/

http://msmvps.com/blogs/lopez/archive/tags/AjLisp/default.aspx
http://msmvps.com/blogs/lopez/archive/tags/AjLogo/default.aspx
http://msmvps.com/blogs/lopez/archive/tags/AjTalk/default.aspx

Mis posts sobre Javascript
http://msmvps.com/blogs/lopez/archive/tags/Javascript/default.aspx

Les agrego algunos enlaces sobre ClojureScript, que no mencioné

Introducing ClojureScript
http://clojure.com/blog/2011/07/22/introducing-clojurescript.html
de @stuartsierra

ClojureScript Rationale
https://github.com/clojure/clojurescript/blob/master/devnotes/cljs.org
de @stuarthalloway

Compiling Clojure to Javascript pt. 1 of n
http://blog.fogus.me/2011/07/21/compiling-clojure-to-javascript-pt1/
de @fogus

Ferret: An Experimental Clojure Compiler
http://nakkaya.com/2011/06/29/ferret-an-experimental-clojure-compiler/

Los enlaces que me interesaron, leí, estudié para esta charla, o los tengo pendientes:

http://delicious.com/ajlopez/clojurescript
http://delicious.com/ajlopez/javascript+parser
http://delicious.com/ajlopez/javascript+compiler
http://delicious.com/ajlopez/javascript+smalltalk

Nos leemos!

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

Ruby Buenos Aires Meetup Marzo 2012

Friday, March 30th, 2012

Ayer tuve el gusto de asistir a mi segunda meetup de Ruby acá en Buenos Aires. Fue en Urban Station, un buen lugar para trabajadores móviles: pueden ir con su notebook y trabajar en una mesita, con WiFi, enchufe, pagando por hora, o alquilar salones chicos de reuniones. La gente de Ruby Argentina consiguió una sala con proyector. Llegué a las 18:20 (empeza 18:30), y me encontré con Esteban, arquitecto, programador PHP, que estaba en Ruby. Mientras esperábamos, aproveché para preguntarle por qué se usa en Arquitectura, me enteré de Build Information Modeling, ver mis enlaces http://delicious.com/ajlopez/bim. Tenía algo con ver con la charla que iba a dar, sobre AjLisp en Ruby (ver mis posts http://ajlopez.wordpress.com/category/ajlisp), porque AutoCad tuvo desde siempre AutoLisp como lenguaje de base de programación.

Poco a poco fue llegando más gente, como @soveran, @maceto, @inkel, creo que llegó @etagwerker pero no pude hablar con él.

El primer disertante fue… moi ;-). Presenté AjLisp en Ruby, ver https://github.com/ajlopez/AjLispRb. Hace dos días, encontré esta presentación:

How Emacs changed my life http://www.slideshare.net/yukihiro_matz/how-emacs-changed-my-life By Yukihiro "Matz", Ruby creator

Que me ayudó a poner la relación entre Lisp y Ruby. Conté algo de la historia de Lisp. Y destaqué que desarrollé AjLispRb usando TDD, desde el principio, para ir practicando y aprendiendo Ruby. Hice algunas demostraciones, mostrando rápidamente lambdas, define, closures y macros. Notablemente, cuando presenté que tiene una sintaxis tipo Java Dot Notation (ver http://jscheme.sourceforge.net/jscheme/doc/javadot.html) para acceder a objetos y clases Ruby, me preguntaron si esto anda en AjLisp:

(.require @Kernel "date”)

(.today @Date)

funcionó! 😉 Ni se me había ocurrido probarlo. En realidad, en vez de “@Kernel” puedo poner “pepe”, e igual termina invocando al método “global” require, tengo que investigar por qué. Jeje… AjLispRb tiene vida propia.

Luego presentó Michel Martens, gran programador Ruby, @soveran, y jugador de Go, ver https://github.com/soveran, por ejemplo, vean su framework web Cuba https://github.com/soveran/cuba. Presentó los elementos de uso de Rack, un tema que me interesa por su historia, relación con Python y otros. Ver mis enlaces http://delicious.com/ajlopez/rack. En un tiempo, quisiera preparar una charla corta sobre el tema, para algún Ruby Meetup u otro lugar.

Y notablemente, presentó algo muy interesante, Bandicoot:

http://bandilab.org/
http://www.readwriteweb.com/hack/2011/07/new-set-based-programming-language-bandicoot.php

Su presentación en:

http://files.soveran.com/bandicoot/ (hecha con https://github.com/nakajima/slidedown, ver https://github.com/soveran/slidedown-skeleton)

Interesante. Maneja conjuntos con operadores de álgebra relacional. Hmmm… interesante Code Kata para Pascual: implementar algo en C#, usando LINQ por debajo. Mis enlaces sobre el tema http://delicious.com/ajlopez/set+programminglanguages

Michel lo usó en un proyecto. Vean que Bandicoot levanta un servidor al que se accede por HTTP, y en su lenguaje se programa los “puntos de entrada” que se exponen por ese servidor HTTP. El escribió un cliente Ruby https://github.com/soveran/rel. También comentó sobre su parser de command line https://github.com/soveran/clap (vean el uso de lambdas de Ruby ahí).

Hubo otros temas que se trataron: el anuncio de Rails Girls  en Buenos Aires:

http://railsgirls.com/buenosaires

Se propuso hacer un Ruby Camp, reunirse para programar, ya sea en un lugar abierto, o en un bar, o en una casa. Se anunció que ya se comenzó a organizar la Ruby Conf de 2012.

Se repartió “merchandising”, varios conseguimos una tarjeta de promoción de Code School http://www.codeschool.com/.

Un poco antes de las 21, se levantó la reunión que siguió con comida, bebida (supongo que agua mineral solamente 😉 en otros lugares de la zona de Palermo. Lo mío es la sopita de pollo, así que regresé a mi cubil principal.

Felicitaciones a la gente de Ruby Argentina por tener una comunidad tan activa y abierta.

Nos leemos!

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

AjLisp en Ruby (2) Contexto con Nombres y Valores

Thursday, December 29th, 2011

Anterior Post

Una de las primeras clases que implemente en AjLispRb es el ambiente (“environment”). Esta vez lo llamé contexto: un diccionaro donde guardar pares nombre/valor, los valores de los átomos con nombre. El código:

module AjLisp
class Context
    def initialize(parent = nil)
        @parent = parent
        @values = Hash.new
    end
    
    def getValue(name)
        if @values.has_key?(name)
            return @values[name]
        end
        
        if @parent != nil
            return @parent.getValue(name)
        end
        
        return nil
    end
    
    def setValue(name, value)
        @values[name] = value
    end
end
end

La clase fue codificada usando TDD (Test-Driven Development), los primeros tests en test/test_context.rb. Algunos tests:

def test_not_defined_is_nil
    context = AjLisp::Context.new
    assert_nil(context.getValue(:foo))
end
def test_set_and_get_value
    context = AjLisp::Context.new
    context.setValue(:foo, "bar")
    assert_equal("bar", context.getValue(:foo))
end
def test_get_value_from_parent
    parent = AjLisp::Context.new
    parent.setValue(:foo, "bar")
    context = AjLisp::Context.new(parent)
    assert_equal("bar", context.getValue(:foo))
end

Inicialmente, yo usaba strings para los nombre, pero ahora estoy usando los símbolos de Ruby como :foo. Tengo un test que asegura la independencia de los valores del contexto padre y del hijo:

def test_override_value_from_parent
    parent = AjLisp::Context.new
    parent.setValue(:foo, "bar")
    context = AjLisp::Context.new(parent)
    context.setValue(:foo, "bar2")
    assert_equal("bar2", context.getValue(:foo))
    assert_equal("bar", parent.getValue(:foo))
end

Cada contexto puede tener un contexto padre. Hay un contexto “tope”, definido lib/ajlisp.rb:

module AjLisp
@context = Context.new
@context.setValue :quote, FPrimitiveQuote.instance
@context.setValue :first, PrimitiveFirst.instance
@context.setValue :rest, PrimitiveRest.instance
@context.setValue :cons, PrimitiveCons.instance
@context.setValue :list, PrimitiveList.instance
@context.setValue :lambda, FPrimitiveLambda.instance
@context.setValue :flambda, FPrimitiveFLambda.instance
@context.setValue :mlambda, FPrimitiveMLambda.instance
@context.setValue :let, FPrimitiveLet.instance
@context.setValue :define, FPrimitiveDefine.instance
@context.setValue :do, FPrimitiveDo.instance
@context.setValue :if, FPrimitiveIf.instance
@context.setValue :definef, FPrimitiveDefinef.instance
@context.setValue :definem, FPrimitiveDefinem.instance
@context.setValue :+, PrimitiveAdd.instance
@context.setValue :-, PrimitiveSubtract.instance
@context.setValue :*, PrimitiveMultiply.instance
@context.setValue :/, PrimitiveDivide.instance
def self.context
    return @context
end
# ...
end

Los nuevos contexts son creado por varias primitivas. En el comienzo, existe el contexto tope definido arriba, como:

Si tenemos que definir una función que retorna el segundo elemento de una lista, podemos usar la primitiva define:

(define second (a) (first (rest a)))

ahora tenemos en el contexto tope una nueva entrada para second:

El contexto tope tiene ahí en esa nueva entrada el valor que representa un lambda  (lambda (a) (first (rest a))  (en realidad, debería aclarar que se guarda el resultado de haber evaluado el lambda, que es un closure (clausura) pero ya llegaremos al tema en próximo post).

Cuando invocamos:

(second (quote (one two three)))

un nuevo contexto se crea, con su padre apuntando al contexto tope (de nuevo, es algo más complejo, veremos clausuras). Ese nuevo contexto tiene un par nombre/valor:

Este contexto es descartado LUEGO de esta evaluaciónThat de second  (puede sobrevivir indirectamente si luego de la evaluación quedó referenciado por una clausura). Cuando definimos un valor simple:

(define one 1)

el contexto tope es modificado, para tener un nuevo par nombre/valor:

Próximos temas: primitivas y formas especiales, su invocación, clausuras, macros, e invocación de métodos nativos de Ruby.

Nos leemos!

Angel “Java” Lopez

http://www.ajlopez.com

http://twitter.com/ajlopez

AjLisp en Ruby (1) Estructura, Clases y Tests

Saturday, December 3rd, 2011

Estoy aprendiendo y practicando Ruby, y como es costumbre, lo hago escribiendo algo interesante para mí: el intérprete AjLisp (hace unos meses lo implementé en Javascript). TDD es mi amigo: escribo un test, lo ejecuto en rojo, codifico para pasarlo a verde, refactorear, y así sigue. El código de este nuevo intérprete, trabajo en progreso, en:

https://github.com/ajlopez/AjLispRb

Inicialmente (pueden ver los logs) escribí todo en un solo archivo (código y tests), siguiendo el simple y claro ejemplo:

http://kanemar.com/2006/03/04/screencast-of-test-driven-development-with-ruby-part-1-a-simple-example/

Vean que Ruby tiene un paquete ‘test/unit’ que ya viene en su instalación, listo para usar. Despues de algo de “research”, dividí el archivo en código de producción y código de pruebas. Quiero llegar a armar una gema (un paquete Ruby, distribuido por el utilitario gems), así que estudié los primeros pasos del tutorial:

http://guides.rubygems.org/

Tengo pendiente de leer y estudiar:

http://speakerdeck.com/u/pat/p/cut-polish-a-guide-to-crafting-gems
http://blog.thepete.net/2010/11/creating-and-publishing-your-first-ruby.html

Así que mi código aún no es una gema. Pero va teniendo la estructura de una:

El directorio lib contiene un solo archivo ajlisp.rb:

require 'ajlisp/list.rb'
require 'ajlisp/named_atom.rb'
require 'ajlisp/context.rb'
require 'ajlisp/string_source.rb'
require 'ajlisp/token.rb'
require 'ajlisp/lexer.rb'
require 'ajlisp/parser.rb'
require 'ajlisp/primitive.rb'
require 'ajlisp/primitive_first.rb'
require 'ajlisp/primitive_rest.rb'
require 'ajlisp/primitive_cons.rb'
require 'ajlisp/primitive_list.rb'
require 'ajlisp/primitive_closure.rb'
require 'ajlisp/fprimitive.rb'
require 'ajlisp/fprimitive_quote.rb'
require 'ajlisp/fprimitive_lambda.rb'
require 'ajlisp/fprimitive_flambda.rb'
require 'ajlisp/fprimitive_let.rb'
require 'ajlisp/fprimitive_closure.rb'
require 'ajlisp/fprimitive_define.rb'
require 'ajlisp/primitive_add.rb'
module AjLisp
@context = Context.new
@context.setValue "quote", FPrimitiveQuote.instance
@context.setValue "first", PrimitiveFirst.instance
@context.setValue "rest", PrimitiveRest.instance
@context.setValue "cons", PrimitiveCons.instance
@context.setValue "list", PrimitiveList.instance
@context.setValue "lambda", FPrimitiveLambda.instance
@context.setValue "flambda", FPrimitiveFLambda.instance
@context.setValue "let", FPrimitiveLet.instance
@context.setValue "define", FPrimitiveDefine.instance
@context.setValue "+", PrimitiveAdd.instance
def self.context
    return @context
end
def self.evaluate(context, item)
    if item.is_a? List or item.is_a? NamedAtom
        return item.evaluate(context)
    end
        
    return item	
end
end

Escribí algunas primitivas (formas normales, y formas especiales: estas últimas no evalúan sus parámetros antes de su aplicación, ejemplos: quote y define). Noten que los archivos adicionales los puse en un subdirectorio ajlisp dentro de lib, ¿por qué? Porque cuando este código sea instalado como una gema, todo el directorio lib estará disponible para require, y si hubiera un archivo ahí, se podría hacer require(‘elarchivo’). Es por eso que los archivos adicionales a ajlisp.rb se colocan en otro lado, evitando colisión de nombres. Se recomienda colocarlos debajo de lib (vean el código de gemas que tienen en su instalación de Ruby, o vean ejemplos en GitHub).

El el directorio test hay un archivo test.rb que incluye a los otros archivos de tests:

require 'ajlisp'
require 'test/unit'
require "test_list.rb"
require "test_named_atom.rb"
require "test_context.rb"
require "test_string_source.rb"
require "test_token.rb"
require "test_lexer.rb"
require "test_parser.rb"
require "test_primitive_first.rb"
require "test_primitive_rest.rb"
require "test_primitive_cons.rb"
require "test_primitive_list.rb"
require "test_primitive_closure.rb"
require "test_primitive_add.rb"
require "test_fprimitive_quote.rb"
require "test_fprimitive_lambda.rb"
require "test_fprimitive_let.rb"
require "test_fprimitive_closure.rb"
require "test_fprimitive_flambda.rb"
require "test_fprimitive_define.rb"
require "test_evaluate"

Pueden ejecutar los tests desde la línea de comando:

ruby –Ilib;test test\test.rb

En Windows, dejé el archivo runtest.cmd conteniendo esta línea. Los parámetros –Ilib;test le indican a Ruby que incluya los directorios lib y test para cuando tenga que resolver un require. De esta forma evito poner directorios explícitos (o usar __FILE__) en los require.

Algo de tests:

require 'ajlisp'
require 'test/unit'
class TestList < Test::Unit::TestCase
#...    
    def test_create_with_first
        list = AjLisp::List.new("foo")
        assert_equal("foo", list.first)
        assert_nil(list.rest)
    end
    
    def test_create_with_first_and_rest
        rest = AjLisp::List.new("bar")
        list = AjLisp::List.new("foo", rest)
        assert_equal("foo", list.first)
        assert_not_nil(list.rest)
        assert_equal("bar", list.rest.first)
        assert_nil(list.rest.rest)
    end
    
    def test_create_from_array
        list = AjLisp::List.make [1, "a", "foo"]
        assert_not_nil list
        assert_equal 1, list.first
        assert_equal "a", list.rest.first
        assert_equal "foo", list.rest.rest.first
        assert_nil list.rest.rest.rest
    end
#..
end

Cada lista en AjLisp es un objeto de esta clase, list.rb:

module AjLisp
class List
    attr_reader :first
    attr_reader :rest
    
    def initialize(first=nil, rest=nil)
        @first = first
        @rest = rest
    end
    
    def evaluate(context)
        form = AjLisp::evaluate(context, @first)
        form.evaluate(context, self)
    end
    
    def self.make(array)
        if array and array.length > 0
            first = array.shift
            
            if first.is_a? Array
                first = make(first)
            elsif first.is_a? Symbol
                first = NamedAtom.new first.to_s
            end
                        
            return List.new first, make(array)
        end 
        
        return nil
    end
end
end

Los méteodos de acceso first y rest son de sólo lectura. Gracias a la naturaleza no tipada de Ruby (facilidad que también encontré en la implementación de Javascript) la implementación de este intérprete es directa, sin mayor “ceremonia de código”.

En mis nuevos tests, ahora incluye el código DENTRO del módulo AjLisp, así me evito de escribir el prefijo AjLisp:: antes de referenciar a una clase:

require 'ajlisp'
require 'test/unit'
module AjLisp
class TestLexer < Test::Unit::TestCase
    def test_get_atom_token
        source = StringSource.new "atom"
        lexer = Lexer.new source
        token = lexer.nextToken
        
        assert_not_nil token
        assert_equal "atom", token.value
        assert_equal TokenType::ATOM, token.type
        assert_nil lexer.nextToken
    end
    def test_get_atom_token_with_spaces
        source = StringSource.new "  atom   "
        lexer = Lexer.new source
        token = lexer.nextToken
        
        assert_not_nil token
        assert_equal "atom", token.value
        assert_equal TokenType::ATOM, token.type
        assert_nil lexer.nextToken
    end
#...
end

Próximos tópicos: algunos detalles de implementación, primitives vs fprimitives, contexto (ambiente anidado con pares nombre/valor), lambdas y closures, el lexer y el parser.

Próximos pasos: completar las primitivas (let, letrec, definef, do, if…), macro (mlambda, definem, expansión de macros…)

Nos leemos!

Angel “Java” Lopez

http://www.ajlopez.com

http://twitter.com/ajlopez

AjLisp en Javascript (Parte 3) Define, Lambda y Closures

Tuesday, September 6th, 2011

Anterior Post

Veamos la definición de nuevas formas en AjLisp, mi intérprete Lisp escrito en Javascript (github repository). Un forma especial clave en AjLisp es la define:

var defineForm = new SpecialForm();
defineForm.eval = function eval(list, env)
{
	var name = list.first().name();
	var value = list.rest().first();
	var body = list.rest().rest();
		
	if (isNil(body)) {
		value = evaluate(value, env);
	}
	else {
		value = new Closure(value, env, body);
	}		
		
	environment[name] = value;
	return value;
}

Se puede usar para definir datos simples globales. Mis primeros tests:

test("Evaluate Simple Expression with Atoms", function() {
	eval("(define one 1)");
	eval("(define two 2)");
	eval("(define three 3)");
	equal(eval("one"), 1);
	equal(eval("(quote one)").asString(), "one");
	equal(eval("(list one two three)").asString(), "(1 2 3)");
	equal(eval("(first (list one two three))"), 1);
	equal(eval("(rest (list one two three))").asString(), "(2 3)");
	equal(eval("(cons one (list two three))").asString(), "(1 2 3)");
});
		

Pero define está preparada también para recibir tres parámetros:

(define mapfirst (fn lst)
  (if (nilp lst)
    nil
    (cons
      (fn (first lst))
      (mapfirst fn (rest lst))
    )
  )
)

El primer parámetro es el nombre de la propiedad a definir en el ambiente (environment) global. El segundo parámetro es una lista de parámetros. El tercero es la forma a aplicar. Entonces, define se puede usar para definir nuevas funciones, formas. Es equivalente a

(define mapfirst (lambda (fn lst)
    (if (nilp lst)
      nil
      (cons
        (fn (first lst))
        (mapfirst fn (rest lst))
      )
    )
  )
)

Vean el lambda. Es una forma especial:

var lambdaForm = new SpecialForm();
lambdaForm.eval = function eval(list, env)
{
    var argnames = list.first();
    var body = list.rest();
    return new Closure(argnames, env, body);
}

Tanto define (con tres parámetros) como lambda terminan creando un Closure. La clausura recibe una lista de nombres de argumentos, un ambiente (closure environment) y un cuerpo. Entonces, cuando un closure se evalúa:

function Closure(argnames, closureenv, body) {
	body = new List(doForm, body);
	
	this.eval = function(args, environment) {
		var newenv = makeEnvironment(argnames, args, closureenv);
		return evaluate(body, newenv);
	};
}
	
Closure.prototype.evaluate = Form.prototype.evaluate;
Closure.prototype.apply = Form.prototype.apply;

La parta clave es el .eval: la evalucación de closure emplea un nuevo environment, basado NO EN EL ACTUAL, sino en el closureenv, el ambiente recibido en el constructor cuando la clausura fue creada. Esta es una típica implementación en un intérprete Lisp.

Próximos temas a discutir en posts: flambda, mlambda, evaluación de macros, y el parser.

Nos leemos!

Angel “Java” Lopez

http://www.ajlopez.com

http://twitter.com/ajlopez

AjLisp en Javascript (Parte 2) Evaluación de Listas, Formas y Formas Especiales

Wednesday, August 31st, 2011

Anterior Post
Siguiente Post

En el anterior post presenté la estructura y creación de átomos y listas. Pero ¿Cómo se evalúa una lista en AjLisp? Como en otras implementaciones de Lisp, la cabeza de la lista apunta a algo (lo que se llama una forma o forma especial) que se aplica al resto de los elementos. Este es el comienzo del proceso de evaluación de una lista:

List.prototype.evaluate = function(environment) 
{
    var form = this.first().evaluate(environment);		
    return form.apply(this, environment);
}	

El primer elemento debe ser un elemento que evaluado, da un objecto con un .apply como méetodo. Hay dos clases de formas: las normales y las especiales. La implementación de Form:

function Form() {
}
Form.prototype.evaluate = function(environment) { return this; }
Form.prototype.apply = function(list, environment) 
{ 
    if (isNil(list)) return this.eval(list, environment);
    var rest = list.rest();
    if (rest != null)
        rest = rest.evaluateList(environment);
    return this.eval(rest, environment); 
}

La implementación de las especiales:

function SpecialForm() {
}
SpecialForm.prototype.evaluate = function(environment) { return this; }
SpecialForm.prototype.apply = function(list, environment) 
{ 
    if (isNil(list)) return this.eval(list, environment);
    return this.eval(list.rest(), environment);
}

¿Notan la diferencia? Los elementos del resto de la lista SON EVALUADOS en una forma normal. Al contrario, una forma especial no los evalúa. ¿Por qué esa diferencia? Las formas especiales son “primitivas” como (if <cond> <then> <else>…) donde las partes <then> <else>… pueden evaluarse o no bajo el control de la forma especial. Vean:

Special Forms in Lisp

Special forms are those expressions in the Lisp language which do not follow normal rules for evaluation. Some such forms are necessary as primitives of the language, while others may be desirable in order to improve readability, control the evaluation environment, implement abstraction and modularity, affect the flow of control, allow extended scoping mechanisms, define functions which accept a variable number of arguments, or achieve greater efficiency. There exist several long-standing mechanisms for specifying the definition of special forms: FEXPR’s, NLAMBDA’s, and MACRO’s.

¿Ejemplos de Form? Los escribí usando instancias, redefiniendo su método eval:

var listForm = new Form();
listForm.eval = function eval(list) 
{
	return list;
}
var nilpForm = new Form();
nilpForm.eval = function eval(list) 
{
	if (isNil(list))
		return true;
		
	return isNil(list.first());
}
var listpForm = new Form();
listpForm.eval = function eval(list) 
{
	if (isNil(list))
		return true;
		
	return isList(list.first());
}

Un ejemplo de forma especial, el ‘if’:

var ifForm = new SpecialForm();
ifForm.eval = function eval(list, env)
{
	var cond = evaluate(list.first(), env);
	var then = list.rest().first();
	var elsebody = list.rest().rest();
	
	if (!isNil(cond) && cond != false)
		return evaluate(then, env);
	while (!isNil(elsebody)) 
	{
		result = evaluate(elsebody.first(), env);
		elsebody = elsebody.rest();
	}
	
	return result;			
}

Se exponen en el enviroment global:

// Environment
var environment = new Environment();
environment.list = listForm;
environment.first = firstForm;
environment.rest = restForm;
environment.cons = consForm;
environment['do'] = doForm;
environment['if'] = ifForm;
// more settings in environment

Temas para próximos posts: environments, closures, lambdas, macros, el parser y TDD.

Nos leemos!

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

AjLisp en Javascript (Parte 1) Atomos, Listas y TDD

Saturday, August 20th, 2011

Siguiente Post

Estoy reescribiendo mi intérprete AjLisp usando Javascript. Pienso que un intérprete Lisp es un buen proyecto para aprender un lenguaje: simple, acotado pero no trivial. Nunca hubiera comenzado este proyecto sin usar TDD (Test-Driven Development): Javascript es muy dinámico y las herramientas que estoy usando (el browser, editor de texto) son limitadas. Sin la ayuda de TDD este proyecto hubiera sido difícil de desarrollar. TDD me divierte, avances en pequeños pasos y me ayuda a explorar e implementar buen diseño.

El código (con un parse, varias formas primitivas implementadas, algo de proceso de macros, trabajo en progreso) está en GitHub:

https://github.com/ajlopez/AjLispJs

El código reside en un solo archivo: https://github.com/ajlopez/AjLispJs/blob/master/src/ajlisp.js

Estoy usando QUnit para los tests:

La implementación usa el patrón namespace:

AjLisp = function() {
// ...
}();

El namespace es el resultado de evaluar una función. Esta función retorna un objeto con los miembros públicos que quiero exponer del namespace:

return {
	// Classes
	List: List,
	Environment: Environment,
	Atom: Atom,
	Closure: Closure,
	Lexer: Lexer,
	TokenType: TokenType,
	Parser: Parser,
	
	// Functions
	makeList: makeList,
	isAtom: isAtom,
	isList: isList,
	isNil: isNil,
	asString: asString,
	evaluate: evaluate,
	
	// Top Environment
	environment: environment
}

Como es usual, un intérprete Lisp debe soportar listas y átomos. Código parcial de mi implementación de lista:

function List(first, rest) {
	function getFirst() {
		return first;
	}
	
	function getRest() {
		return rest;
	}
	
	this.first = getFirst;
	this.rest = getRest;
}
List.prototype.isAtom = function() { return false; }
List.prototype.isList = function() { return true; }
List.prototype.evaluate = function(environment) 
{
	var form = this.first().evaluate(environment);		
	return form.apply(this, environment);
}	
// ...

Noten que first y rest están encapsuladas en el closure del constructor. Son inmutables y puede accederse solamente desde funciones alist.first() y alist.last(). Debería evaluar el impacto de usar un closure en la construcción de una lista. Pero parece que es relativamente liviano.

La implementación de Atom es simple:

function Atom(name) {
	this.evaluate = function(environment) {
		return environment.getValue(name);
	};
	
	this.name = function() { return name; };
}
Atom.prototype.isAtom = function() { return true; }
Atom.prototype.isList = function() { return false; }
Atom.prototype.asString = function() { return this.name(); }
Atom.prototype.equals = function(atom)
{
	if (isNil(atom) || !isAtom(atom))
		return false;
		
	return this.name() == atom.name();
}

Su evaluación se basa en un environment (un diccionario que asocia nombres con valores, pero que pueden estar anidados: un environment puede ser padre de otro) y en el nombre del átomo. Números, strings son objetos Javascript y no necesitan ser implementados como átomos. En una implementación “clásica” de Lisp todos los elementos son SExpressions (expresiones simbólica) capaces de ser evaluadas. Ahora, yo tengo un AjLisp.evaluate que acepta cualquier objeto Javascript y detecta si puede ser evaluado en un environment:

function evaluate(x, environment)
{
	if (x === null || x === undefined)
		return x;
		
	if (x.evaluate != undefined && typeof(x.evaluate) == "function")
		return x.evaluate(environment);
		
	return x;
}

Test de Atomos:

test("Atom", function() {
	var environment = new AjLisp.Environment();
	environment.setValue("one", 1);
	var one = new AjLisp.Atom("one");
	equal(one.evaluate(environment), 1);
	ok(one.isAtom());
	equal(one.isList(), false);
	ok(AjLisp.isAtom(one));
	equal(AjLisp.isList(one), false);
	equal(one.asString(), "one");
	equal(one.equals(one), true);
	var one2 = new AjLisp.Atom("one");
	equal(one.equals(one2), true);
});

Test probando la conducta de Listas:

test("List", function() {
	var list = new AjLisp.List(1,2);
	equals(list.first(), 1);
	equals(list.rest(), 2);
	equal(list.isAtom(),false);
	equal(list.isList(),true);
	equal(AjLisp.isAtom(list), false);
	equal(AjLisp.isList(list), true);
	equal(list.asString(), "(1.2)");
	equal(list.equals(list), true);
	var list2 = new AjLisp.List(1,2);
	equal(list.equals(list2), true);
	equal(list2.equals(list), true);
	var list3 = AjLisp.makeList(1,2,3);
	equal(list.equals(list3), false);
	equal(list3.equals(list), false);
	list = AjLisp.makeList(null, null);
	ok(list.first() === null);
	ok(list.rest().first() === null);
});

Temas pendientes: implementación de environment, evaluación de listas, formas y formas especiales, el parser, lambda, mlambda, flambda…. Me divieggto como loco! 😉 😉

Nos leemos!

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

Presentando Programación Funcional, AjLisp y Clojure

Friday, November 5th, 2010

Ayer, Jueves 4 de Noviembre, tuve el placer de compartir una charla con @MartinSalias y @RodolfoF, sobre Programación Funcional. La dimos como una charla del nuevo emprendimiento de Martin:

http://www.codeandbeyond.org/

El lugar fue las instalaciones de @Southworks, donde tuvimos proyector, sillas, sonido, y catering (incluyendo cervezas!! ;-). El evento quedó grabado, así que esperamos que Martín lo publique.

Un resumen de lo que dieron Martín y Rodolfo: Martín presentó Programación Funcional en general, comentando sobre Cálculo Lambda, Lisp y la historia de los lenguajes de programación funcional, como ML, Caml, F# y otros. Luego me tocó mi turno, más abajo doy detalles. Tercer parte, de nuevo Martín mostrando F#, y finalmente, Rodolfo mostrando que C# desde el principio es funcional, y dando ejemplos de código procedural vs funcional.

No desesperen, entonces, que todo quedará disponible para verlo en línea.

Mientras, en este post, quería dejar enlaces y comentarios breves de mi intervención en la charla.

Primero, la primera parte presentación se basó en una que ya había dado para @southworks: LambdaPresentation.pptx.

La presentación de ayer en LispClojure.pptx (no es gran cosa, más que algunos enlaces, tiene varios slides en blanco, ver las notas, donde hay código de ejemplo).

Mostré código de cálculo lambda de mi proyecto AjLambda:

Presenting AjLambda: Lambda Calculus Implementation in C#
Presentando AjLambda: implementación de Cálculo Lambda en C#

Si quieren conocer sobre cálculo lambda, desde las matemáticas y lógica, dejé historia y enlaces que usé en

Notas sobre Cálculo Lambda

Trabajé unos minutos mostrando Lambdas en AjLisp. Posts sobre el proyecto AjLisp. Ahí van a encontrar otras implementaciones, como AjScheme, y un AjSharpure, (Work in Progress).

La parte de Clojure la basé en la más larga, detallada y excelente charla de @unclebob:

Uncle Bob Martin’s "Clojure – Up Close and Personal"

Usé el ejemplo de multithreading en Clojure con transacciones en memoria:

https://github.com/sfraser/MultithreadedGameOfLife

Hace ya unos años, escribí sobre Recursos de F# y Programación Funcional.

Mis posts sobre F#
Mis posts sobre Programación Funcional

Mis enlaces:

http://delicious.com/ajlopez/functionalprogramming
http://delicious.com/ajlopez/lisp
http://delicious.com/ajlopez/f#
http://delicious.com/ajlopez/clojure
http://delicious.com/ajlopez/monads
http://delicious.com/ajlopez/lambda
http://delicious.com/ajlopez/scheme

Para los que les interesa Lisp, les recomiendo el libro y más:

Structure and Interpretation of Computer Programs
Video Lectures by Hal Abelson and Gerald Jay Sussman
Structure and Interpretation of Computer Programs adapted for the Clojure programming language
http://delicious.com/ajlopez/sicp

Algo más matemático, que mencioné al pasar:

http://delicious.com/ajlopez/categorytheory
http://www.delicious.com/ajlopez/grothendieck
Alexander Grothendieck
Nicolas Bourbaki

Nos leemos!

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