viernes, 7 de enero de 2011

Raros Lenguajes Nuevos: Scotch

Scotch

Siguiendo con la investigación sobre lenguajes experimentales o novedosos, hoy les presento Scotch, una creación de Ben Morris.

Ben empezó este proyecto de lenguaje como un ejercicio en Haskell, pero se entusiasmó con el resultado y sigue adelante, después de haberlo dejado abierto en GitHub para contribuciones de cualquiera.

Scotch es un lenguaje funcional que trata de mantener una sintaxis minimalista y expresiva, y agrega algunas características particulares a gusto de su creador:

La asignación es siempre no estricta (lazy), de manera que si definimos "a = b", no estamos pasando valores, sino asignando una expresión. Si luego decimos que "b = 42", al inspeccionar el resultado de "a", se va a evaluar la secuencia y obtendremos 42.

A diferencia de Haskell mismo, Scotch no es puro, y se pueden definir variables que mantengan estado, por lo que no queda libres de efectos colaterales como en lenguajes funcionales puros; también es débilmente tipado, lo que implica que podemos sumar números y strings, por ejemplo, y en lugar de dar error hace conversiones implícitas (siempre que pueda).

Otra característica interesante es la resolución implícita en base a reconocimiento de patrones. Por ejemplo, para definir una función que calcule el factorial de un número, se hacen dos definiciones, una genérica y una específica:

fact(n) = n * fact(n-1)
fact(0) = 1

La primera línea es la definición recursiva clásica, pero por si sola tiene el problema de que nunca terminaría, por lo que se puede definir el caso particular para cuando sea llamada con 0, de manera que en lugar de seguir llamándose a sí misma devuelva 1.

Casi toda la librería de clases está basada en este mecanismo, utilizando recursividad de cabeza y cola (head/tail) y utilizando patrones para manejar los casos límites donde debe cortarse la recursión.

Como casi todos los lenguajes funcionales, permite aplicación parcial y currying, como en este ejemplo:

apply(f, x) = f(x)
add(x, y) = x + y
apply(add(10), 20)

Aquí "apply" se define como la ejecución de una función que recibirá "x" como parámetro. La función "add" recibe dos parámetros y los suma, pero podemos aplicarla parcialmente como en el caso final, utilizando "apply".

También tiene soporte para hilos de ejecución livianos (lightweight threads), o sea que no son hilos reales del sistema operativo, sino implementados por el lenguaje mismo (en este caso utiliza los que provee Haskell).

Finalmente, el autor agregó Tipos de Datos Algebraicos (ADTs) que son como objetos livianos sin definición de clase, y funciones anónimas (lambdas).

La gracia principal de ste intérprete es que la implementación es muy pequeña y es un buen ejercicio tanto de implementación de un lenguaje como de Haskell mismo.