Archive

Archive for February, 2011

Ejecución de programas Gacela en el navegador (rectificación)

February 28th, 2011 No comments

Y es que a veces hay que meterse una patata en la boca antes de decir nada. O coger una patata en cada mano antes de bloguear nada.

En el post anterior sobre cargar ficheros con Javascript dije que con Ajax no se podía, que era necesario usar iframes, etc, etc… ¡¡Mentira cochina!! Pues claro que se puede, y resulta mucho más fácil.

El código para cargar un programa Lisp, compilarlo y ejecutarlo sería así:

<html>
    <head>
        <script type="text/javascript" src="lisp2js.js"></script>
        <script id="head_js" type="text/javascript"></script>
        <script type="text/javascript">
            function cargar (fichero) {
                var req = new XMLHttpRequest();
                req.open('GET', fichero, false);
                req.send(null);
                if (req.status == 200) {
                    var lisp_code = req.responseText;
                    var js_code = string2js(lisp_code);
                    document.getElementById('head_js').text = js_code;
                }
            }
        </script>
    </head>

    <body onLoad="cargar('programa.lisp'); init();">
    </body>
</html>

Esta sería la versión síncrona, aunque también se puede hacer de forma asíncrona. Se pueden ver más ejemplos en Using XMLHttpRequest.

Categories: Uncategorized Tags:

Ejecución de programas Gacela en el navegador

February 25th, 2011 No comments

Actualización: Todo lo explicado en esta entrada puede hacerse mucho mejor usando el objeto XMLHttpRequest, tal como cuento en Ejecución de programas Gacela en el navegador (rectificación). Si quieres saber cómo no hacerlo, sigue leyendo :-D

El proyecto Gacela, en el que llevo trabajando cerca de dos años y medio, está formado a su vez por tres subproyectos:

  • Gacela, la definición del lenguaje y el compilador / intérprete, que funciona localmente en el ordenador.
  • Lisp2js, el compilador de Lisp a Javascript que permite traducir programas Gacela y ejecutarlos en una página web.
  • Gacela on Wheels, un entorno web para el desarrollo de juegos con Gacela.

Estos últimos meses estoy más centrado en Lisp2js y en la posibilidad de ejecutar en el navegador programas escritos con Gacela. La idea es poder incluir en una página web un código en Javascript del estilo file2js(‘mi_juego.lisp’); iniciar_juego(); que traduzca el código en Lisp a código en Javascript, lo incruste en la página y lo ejecute. Pero me encontré con una dificultad que no había previsto y que me sorprendió, y es que Javascript por motivos de seguridad no tiene funciones para trabajar con ficheros.

A continuación explicaré de qué forma podemos cargar ficheros con Javascript y de paso explicaré cómo Gacela consigue añadir código Javascript a una página y ejecutarlo. Para otro día queda el funcionamiento interno de Lisp2js.

La forma de acceder a un fichero con Javascript (siempre estoy hablando de un fichero que se encuentre en el mismo dominio) es usando el elemento iframe. Hay otras formas, como usando Ajax, pero eso requiere usar algo de PHP en el servidor y la idea es que el invento pueda funcionar localmente sin necesidad de servidor web.

El código que hará funcionar todo es el siguiente:

<html>
    <head>
        <script type="text/javascript" src="lisp2js.js"></script>
        <script id="head_js" type="text/javascript"></script>
        <script type="text/javascript">
            function cargar (fichero, func) {
                var el = document.getElementById('mi_iframe');
                if (el == null) {
                    var el = document.createElement("iframe");
                    el.setAttribute('id', 'mi_iframe');
                    el.onload = function() { ejecutar_mi_codigo(func); }
                    el.style.display='none';
                    document.body.appendChild(el);
                }
                el.setAttribute('src', fichero);
            }

            function ejecutar_mi_codigo (func) {
                var el = document.getElementById('mi_iframe');
                var lisp_code = el.contentWindow.document.body.textContent || el.contentWindow.document.body.innerText;
                var js_code = string2js(lisp_code);
                document.getElementById('head_js').text = js_code;
                func();
            }
        </script>
    </head>

    <body onLoad="cargar('programa.lisp', function() { init(); });">
    </body>
</html>

Se usan dos funciones, una para crear el iframe e indicarle el fichero que debe abrir y otra para ejecutar el código que estamos cargando. Se hace así porque iframe funciona de forma asíncrona, por lo que le decimos lo que debe hacer cuando tenga todo el contenido usando la propiedad onload.

La primera función, cargar, se ocupa de crear el iframe, pero si ya existe se limita a indicarle el fichero a cargar. Aunque en este ejemplo no tiene mucho sentido, sí que lo tiene si tuvieramos que cargar varios ficheros.

La segunda función, ejecutar_mi_codigo, se lanza cuando el iframe acaba de cargar el fichero. Usando las propiedas textContent o innerText (esto depende del navegador) recogemos el código Lisp, lo traducimos a Javascript y lo insertamos en su correspondiente sección en la cabecera. Finalmente iniciamos la ejecución del código.

Así, aunque de forma más transparante, Gacela es capaz de cargar código Lisp en una página web y ejecutarlo. Es decir, que el mismo código se ejecuta de la misma forma localmente en un ordenador o de forma remota a través del navegador, que es lo que se pretende.

Categories: Uncategorized Tags:

No quieren que copiemos… pues no lo hagamos

February 20th, 2011 No comments

No voy a entrar a hablar sobre la “ley Sinde”; mucho se ha hablado ya y gente como Ricardo Galli o Enrique Dans lo hacen mucho mejor de cómo lo haría yo. Que esa ley atenta contra derechos constitucionales es algo obvio y si ha salido adelante ha sido por presiones políticas y económicas que poco tienen que ver con los valores éticos que se supone deberían defender los “padres de la patria”.

Simplemente quiero hacer una pequeña reflexión al respecto. Todas estas leyes relacionadas con derechos de autor cuyo objetivo es que la gente no pueda ejercer su libre derecho a la copia seguirán surgiendo con el paso de los años, ya que son promovidas por una industria poderosa con el único afán de controlar el mercado, controlar a las personas y convertir cualquier acción de esas personas en dinero, aunque ese control vaya totalmente en contra del bién común y destruya cultura en vez de crearla.

Lo mismo ocurre con los programas, y de hecho las leyes sobre derechos de autor en el software son más restrictivas que en el caso de la cultura. Por eso muchos no usamos programas de Microsoft (no quieres que los copie; pues no los copiaré) ni de Apple (no quieres que los copie; pues no los copiaré) ni de muchas otras empresas. Usamos programas libres de personas o empresas que no nos prohiben usar esos programas libremente.

Y lo mismo ocurre con la música o las películas. No tengo ningún problema en comprar un disco, y el precio no me importa demasiado. Si el disco es caro pero me gusta mucho posiblemente lo compraré. Pero una vez comprado (disco, libro, lo que sea) quiero poder copiarlo, fotocopiarlo, distribuirlo entre mis amigos, etc, etc. Porque si no puedo hacerlo no me interesa ni regalado.

Existen alternativas libres como Jamendo o Magnatune, o podemos encontrar cultura libre en abundancia usando el catálogo de Creative Commons, con lo cual yo me digo, si no quieren que copiemos sus obras privativas… pues no lo hagamos.

Categories: Uncategorized Tags:

La recursividad “infinita” de Lisp

February 11th, 2011 No comments

La posibilidad de aprovechar toda la potencia de la recursividad es uno de los puntos fuertes (hay tantos) de los lenguajes funcionales y aunque voy a hablar de Lisp, ya que es el lenguaje funcional que mejor conozco, lo que voy a decir es aplicable a Scheme, Haskell, etc.

Para la explicación usaré el típico ejemplo de calcular el factorial de un número. El código en Lisp para realizar el cálculo (que nadie se asuste con los paréntesis) sería:

(defun factorial (n)
   (cond ((= n 1) 1)
         (t (* n (factorial (- n 1))))))

La misma función escrita en C sería la siguiente:

int factorial (int n) {
    if (n == 1)
        return 1;
    else
        return n * factorial (n - 1);
}

Sin embargo, esta forma de calcular el factorial de un número suele encontrarse únicamente en libros de programación para explicar el mecanismo de la recursividad. Cualquier programador sabe que cada vez que llamamos a una función el sistema operativo almacena en la pila el estado actual del programa para recuperarlo después cuando vuelva de la llamada a la función, con lo que si queremos calcular el factorial de un número muy grande corremos el riesgo de sufrir un desbordamiento de pila con efectos un tanto desagradables para nuestro programa.

Por esa razón los programadores de C calcularían el factorial de la siguiente forma:

int factorial (int n) {
    int r = 1, n2 = n;

    while (n2 > 1) {
        r = r * n2;
        n2--;
    }

    return r;
}

Ahora evitamos el problema del desbordamiento de pila y el programa, al ser iterativo, es mucho más rápido, aunque el código no resulta tan fácil de leer ni tan lógico como la versión recursiva.

Pero, en contra de lo que podría esperarse, el código en Lisp funciona igual de rápido que el código en C y además, podemos calcular factoriales de números inmensos sin que la pila se inmute. ¿Cómo es posible? Es posible gracias al trabajo del intérprete de Lisp y a una técnica conocida como Tail Recursion (recursividad por cola).

Lo que hace el intérprete de Lisp es sustituir nuestra función por esta otra:

(defun factorial (n &optional (r 1))
    (cond ((= n 1) r)
          (t (factorial (- n 1) (* r n)))))

Si nos fijamos bien veremos que la nueva función no necesita volver sobre sus pasos para calcular el factorial, sino que va calculando el resultado antes de la llamada recursiva. Esto permite que no sea necesario usar la pila, ya que no hace falta regresar a través de todas las llamadas, sino que la última es la que devolverá el resultado directamente.

Si bien es cierto que muchos compiladores de lenguajes imperativos como C tienen en cuenta este tipo de funciones y las tratan como funciones iterativas, los intérpretes y compiladores de lenguajes funcionales lo hacen de forma implícita, lo que permite un código mucho más claro y legible.

Categories: Uncategorized Tags:

Debian 6.0 “Squeeze” publicada

February 6th, 2011 No comments

Acaba de publicarse la nueva versión de Debian, “Squeeze”, con muchas mejoras que harán las delicias de la comunidad, aunque para mi la más importante es que venga de serie con un kernel Linux totalmente libre de drivers privativos.

Esta decisión de Debian de separar claramente lo que es libre de lo que no ha convencido al equipo de gNewSense para basar la futura gNewSense 3.0 en “Squeeze” en vez de Ubuntu, lo que les permitirá sacar versiones más rapidamente y disfrutar de la arquitectura MIPS, necesaria para correr gNewSense en los ordenadores Lemote Yeelong, que funcionan con hardware totalmente libre.

El proyecto GNU, aparte de ser un proyecto tecnológico, es una forma de mejorar la sociedad, de hacer comprender la importancia de primar los derechos de las personas sobre los intereses corporativos, y el hecho de que la gente tenga cada vez más clara la necesidad de separar el software libre del que no lo es, es un gran paso en esa dirección.

¡¡Enhorabuena, Debian!!

Categories: Uncategorized Tags: