El mundo de la informática se ha vuelto sumamente complejo hoy en día, cientos de librerías, docenas de lenguajes de programación, estas variables hacen del desarrollo de software una pesadilla. sería muy interesante tener un único (o al menos principal) medio de expresión del software, que la gran mayoría aceptara como la manera de comunicarse con las máquinas.
Vamos a explorar una de las maneras de atacar el problema de la complejidad del software, intentaremos crear un lenguaje ideal, el lenguaje de nuestros sueños, que ofrezca todos los mecanismos que nos permitan expresarnos de la manera que mejor nos parezca para resolver un problema dado, un lenguaje que soporte todos los paradigmas actuales de la programación. Ante todo, nuestro lenguaje debe soportar la programación estructurada, la programación orientada a objetos (OOP) en todas sus variantes, la programación funcional y la programación concurrente.
Deberíamos ser incluso más generales, diseñaremos un lenguaje sencillo pero extensible, así, podríamos partir de una base extremadamente simple, que nos permita implementar nuevas funcionalidades o extensiones a partir de la misma, así además de lograr implementar los paradigmas actuales de la programación, tendremos una muy buena oportunidad de implementar los paradigmas que se inventen en el futuro, cuando estos aparezcan.
Como nuestro lenguaje pretende ser extensible lo llamaremos LPX por las siglas de Lenguaje de Programación eXtensible, que no es muy original pero captura la idea.
Queremos que LPX no solo sea una moda, que sea la sólida base para una plataforma que dure al menos hasta que las máquinas adquieran la suficiente inteligencia para describirles los problemas y que ellas mismas nos den la solución.
Deseamos que LPX sea adoptado ampliamente y por ello debemos diseñarlo para que sea fácil de aprender y muy fácil de leer incluso para personas sin nociones de programación, permitiendo a los usuarios con un mínimo entrenamiento hacer modificaciones sencillas a programas existentes. Tal vez esto parezca una utopía, sin embargo, son los usuarios prácticamente sin entrenamiento, los que universalmente extienden Excel haciendo macros en Visual Basic para Aplicaciones (VBA), LPX debería ser más fácil de aprender que VBA.
LPX será mejor si tiene pocos elementos de sintaxis, evitaremos la mayor cantidad posible de signos de puntuación, palabras reservadas, y reglas de construcción de oraciones. Por ello quedan descartados rápidamente lenguajes como Perl (¡que lastima!) y C++, mientras que lenguajes como Ruby, Java y Pascal podrían ser opciones viables, aunque intentaremos que sea aún mas simple.
Un lenguaje que se simplifica la sintaxis al máximo es Python, y de hecho podría servirnos, si no fuera por su esquema de sintaxis diagramada, donde los espacios en blanco especifican la estructura del programa, es antinatural para casi cualquier persona, además complica las herramientas, pues hasta el compilador tiene problemas con esto, así que lo descartaremos.
Copiar una sintaxis preexistente es lo más fácil cuando se quiere diseñar un nuevo lenguaje, porque se puede reutilizar el código de las herramientas existentes y hasta parte de la plataforma operacional; además es importante que nuestro lenguaje sea fácil de manipular para facilitar el desarrollo de herramientas como IDEs y generadores de código que son un factor importante en la adopción del lenguaje.
Aunque pareciera que nos estamos quedando sin opciones, hay todavía una sintaxis sencilla, que tiene poquísimas reglas de construcción, es fácil de manipular automáticamente, está ampliamente difundida y es extensible: ¡ XML !. Si además evitamos los atributos en las marcas de XML y algunas otras características exóticas, su aprendizaje se reduce a saber que una marca se arma con <nombre>contenido</nombre> como ¡ única regla de sintaxis !.
Debo desviarme un instante de la discusión para advertir que estoy muy consciente de que hay mucho más que sintaxis en la barrera de adopción de un lenguaje, la semántica (el significado) también es importante, y por ello LPX tendrá las capacidades de cualquier lenguaje procedimental (asignación y secuencia) y también tendrá funciones de orden superior (higher order functions), que es solo un nombre rimbombante para las funciones que reciben, manipulan o retornan otras funciones, por ejemplo en Perl (hubiera preferido poner un ejemplo en Java, pero no tiene esta capacidad, afortunadamente hay lenguajes más útiles):
sub fold { my ($func, $valor, $lista) = @_;
for my $elemento ( @$lista ) {
$valor = $func->($elemento, $valor)
}
$valor;
}
my $sumar = sub { my ($a,$b) = @_; $a + $b };
my $multiplicar = sub { my ($a,$b) = @_; $a * $b };
print fold($sumar, 0, [1, 2, 3, 4, 5]), "\n";
print fold($multiplicar, 1, [1, 2, 3, 4, 5]), "\n";
La función
fold
recibe una función, un valor inicial y una lista para aplicar la función a todos los elementos de la lista para lograr una acumulación, así la última línea del ejemplo calcula el producto de los elementos en la lista y la penúltima calcula la suma.
Espero que el ejemplo deje claro que está técnica es muy útil aunque solo sea para reutilizar código, pero también ilustra porque Java es un lenguaje limitado y porque la sintaxis de Perl fue la primera en ser descartada.
Habiéndome cuidado de que me reclamen los conocedores, ahora solo debemos hacernos una idea de como luce nuestro lenguaje.
Una expresión como a+b*15 sería algo como:
<sum>
<var>a</var>
<mult>
<var>b</var>
<num>15</num>
</mult>
</sum>
Una llamada a una función:
<factorial>
<param><num>10</num></param>
</factorial>
Ummm??, me da la impresión que el lenguaje es fácil de entender, sin embargo, está algo sobrecargado, además estamos introduciendo muchas palabras, vamos a hacer la función factorial para ver cómo luce:
<define>
<func>factorial</func>
<param>n</param>
<body>
<if>
<cond><lt><var>n</var><num>2<num></lt></cond>
<then>
<return><num>1</num></return>
</then>
<else>
<return>
<mult><var>n</var>
<factorial>
<subst><var>n</var><num>1<num></subst>
</factorial>
</mult>
</return>
</else>
</if>
</body>
</define>
Definitivamente sufrimos del problema de siempre en XML, las marcas terminan resaltando mucho más que los datos (en este caso, el algoritmo). Podríamos remediar parte del problema si elimináramos algunas de las marcas complicando algo nuestro compilador para reconocer números, nombres y algunas secuencias de construcciones separadas por espacios en blanco. Así una expresión como:
<lt><var>n</var><num>2</num></lt>
se podría simplificar a:
<lt>n 2</lt>
Sin embargo nos interesa mantener esta última estructura, pues de este modo
<lt>
puede ser un operador incluido en el lenguaje o una llamada a una función como en:
<factorial>n</factorial>
, lo que nos permitirá extender el lenguaje
ad infinitum, agregando funciones. También eliminaremos la necesidad de especificar el valor de retorno y asumiremos que el último valor evaluado por una función es el valor de retorno (tenia que dejar algo de Perl). Veamos como luce ahora LPX:
<define>
<func>factorial n</func>
<body>
<if>
<cond><lt>n 2</lt></cond>
<then>1</then>
<else>
<mult><var>n</var>
<factorial>
<subst>n 1</subst>
</factorial>
</mult>
</else>
</if>
</body>
</define>
Con estos cambios hemos perdido algo de la flexibilidad de XML, y la posibilidad de procesar todos los aspectos de nuestro programa con las herramientas existentes. Sin embargo, todavía LPX es fácil de procesar automáticamente, aunque desafortunadamente no tan fácil de aprender y menos de leer. Entre otras, no hemos eliminado todas las secuencias. Por ejemplo si asumimos que <if> siempre tiene tres elementos (cond, then, else) separados por blancos, podríamos simplificar aún más el lenguaje a costa de introducir secuencias.
Una vez comprobado que perder algunos beneficios puede hacer LPX más transparente. Podemos transformar las marcas de XML, para escribirlas de forma diferente. Así, en vez de escribir
<marca>contenido</marca>
, escribiremos
<marca contenido>
, de esta manera se mantienen las propiedades de facilidad de procesamiento y la claridad aumenta notablemente:
<define <factorial n>
<if <lt n 2>
1
<mult n <factorial <subst n 1>>>
>
>
Ahora sí estamos avanzando, se ve sencillo, fácil de aprender y de leer, sin embargo, sería interesante poder utilizar marcas que no fueran nombres, sino símbolos. Esto permitiría escribir:
<mult n <factorial <subst n 1>>>
de una manera más natural:
<* n <factorial <- n 1>>>
Claro que ya no sería tan fácil con <lt n 2> pues <<n 2> se prestaría a confusión, pero esto se arregla fácilmente reemplazando '<' y '>' por '{' y '}', quedando así:
{define {factorial n}
{if {< n 2}
1
{* n {factorial {- n 1}}}
}
}
Perfecto, fácil de entender, fácil de aprender, fácil de extender infinitamente y fácil de manipular. Ahora solo tenemos que ponernos a trabajar en un compilador, un interpretador y comenzar a usarlo en todos partes.
Pero no nos apresuremos, se me ocurre una idea para facilitarnos el trabajo (luego les digo porque), en vez de usar '{' y '}' podríamos utilizar '(' y ')':
(define (factorial n)
(if (< n 2)
1
(* n (factorial (- n 1)))
)
)
Creo que me gustaba más como se veía anteriormente, aunque esto puede ser simplemente porque antes se parecía más a Perl (a estas alturas se deben imaginar que me gusta Perl). Pero, como dije anteriormente, el cambio no fue un capricho, estaba esperando reutilizar algunas herramientas ya existentes.
En efecto, ¡ ya ese lenguaje existe !
Bienvenidos a Lisp, un lenguaje sencillo, fácil de aprender y manipular automáticamente, creado en 1958. Tiene hoy la misma vigencia de siempre, la forma de su sintaxis ha permitido el desarrollo de herramientas de procesamiento que le dan la capacidad de extenderse a sí mismo, y adaptarse a cualquier paradigma inventado o por inventar.
Caracterizado como ``el lenguaje de programación programable'', Lisp ha sido capaz de adaptarse a nuevos paradigmas de programación, debido a su capacidad de extenderse a sí mismo, así es como hoy en día maneja objetos mejor que casi cualquier otro incluidos Java y C++, aunque la aparición de la programación orientada a objetos sucede casi tres décadas después de la invención de Lisp.
En Lisp se utilizaba la
orientación a aspectos utilizando funciones de orden superior antes de que se inventara la programación estructurada, pero además las funciones de orden superior logran que ese concepto sea tan natural, que ningún programador de Lisp puede entender como alguien puede ser capaz de soportar cosas como AspectJ.
En Lisp se hacían programas genéricos décadas antes de que la programación genérica se pusiera de moda. Las plantillas de C++ palidecen con respecto al sistema de metaprogramación (macros) de Lisp, que permite extender el lenguaje prácticamente sin ningún límite, y los macros ya eran populares para cuando se conciben las plantillas de C++.
Lisp puede manipular listas de elementos de forma simple, efectiva y eficiente, en efecto su nombre viene de LISt Processor, y las listas en Lisp se representan como elementos encerrados entre paréntesis:
(1 2 3 esta es una lista en lisp 4 5 6)
Un programa en Lisp, es también una lista de Lisp, así que procesarse a si mismo es muy natural, una característica que que ha sido mucho valor en el campo de la inteligencia artificial.
Lisp se puede compilar
eficientemente a lenguaje de máquina, logrando un rendimiento y tamaño similar al de programas equivalentes de lenguaje C, pero es muy fácil de interpretar con una sencilla máquina virtual, que podría funcionar con holgura en cualquier reloj de pulsera.
Lisp permite implementar concurrencia eficiente y segura con mínimas modificaciones al lenguaje (vean
Termite, o mejor aún,
pruebenlo).
A finales de los 80 cuando la gente se da cuenta de que los punteros son malos, en vez de mirar a los lados, o incluso hacia atrás, se ponen a hacer algo completamente nuevo, el gran drama del ``no se inventó aquí'', así nace Java, un lenguaje moderno cuyas características más resaltantes para la época eran:
Dios mio! Lisp ya tenía 25 años con esas características cuando los diseñadores de Sun comenzaron a concebir Java.
Cuando Netscape decide agregar programas a las páginas web desarrollaron Javascript, ignorando que en esa época, el lenguaje para procesar HTML era
DSSSL, que es prácticamente un subconjunto de Lisp.
La
mayoría de la gente opina que XML ha sido un gran avance para la informática porque permite la expresión de cualquier jerarquía de datos con mucha facilidad y flexibilidad, estas ventajas evidentes solo son comparables con la ofuscación que le produce a los datos mismos, ¿recuerdan nuestro primer intento de una sintaxis para LPX?, sin embargo XML y las listas de Lisp son
isomorfas (una palabrota para decir equivalentes), pero con una sintaxis mucho más sencilla. Si todo el sistema de XML se hubiera basado en las expresiones S (las listas de Lisp), la mayoría de las herramientas hubieran estado listas antes de comenzar el diseño.
No puedo imaginar la cantidad de enredos, dificultades e ineficiencias que ha provocado la combinación XML/javascipt, sobre todo cuando ya existía una plataforma, simple y eficiente para manejar todo.
En publicaciones recientes como
CREST (Computational
REST), los investigadores "descubren" que los sistemas distribuidos se pueden ver como una sola aplicación donde el estado de la misma se distribuye mediante continuaciones, mientras hay sistemas en Lisp que llevan años utilizando esos mecanismos.
Durante el desarrollo de las bases de datos relacionales, se inventó SQL (en 1974) como lenguaje fácil para efectuar consultas, pero tomando en cuenta que una entidad (tabla) no es más que una lista de tuplas (registros) que a su vez son listas de elementos (campos), deberíamos suponer que Lisp hubiera sido ideal para hacer el trabajo, pues si lo era, y todavía lo es, pero de haberlo usado como lenguaje de consultas, hoy utilizaríamos el mismo lenguaje para consultar bases de datos relacionales, bases de datos jerárquicas y bases de datos orientadas a objetos con la misma interfaz, da tristeza lo que pudo haber sido y no fue.
Aún hoy se discute como agregar
clausuras, y concurrencia eficiente y segura en Java, cuando Lisp tenía estas capacidades para el momento en que Java estaba siendo diseñado.
Y entonces, ¿por qué la gran mayoría de los programadores usa C++, Java o lenguajes similares aunque probablemente mejores?, la verdad es que solo puedo pensar en tres razones: