usar - se crea lisp
¿En qué sentido son lenguas como Elixir y Julia homoicónicas? (1)
La homoiconicidad en Lisp es fácil de ver:
(+ 1 2)
es la llamada a la función a +
con 1
, 2
como argumentos, además de ser una lista que contiene +
, 1
y 2
. Es simultáneamente código y datos.
En un lenguaje como Julia, sin embargo:
1 + 2
Sé que podemos analizar esto en un Expr
en Julia:
:(1 + 2)
Y luego podemos obtener el AST y manipularlo:
julia> Meta.show_sexpr(:(1+2)) (:call, :+, 1, 2)
Entonces, podemos manipular el AST de un programa en Julia (y Elixir). Pero, ¿son homoicónicos en el mismo sentido que Lisp? ¿Algún fragmento de código es realmente una estructura de datos en el propio lenguaje?
No veo cómo el código como 1 + 2
en Julia es, inmediatamente, datos como (+ 1 2)
en Lisp es solo una lista. ¿Sigue siendo homicónico, entonces?
En palabras de Bill Clinton, "Depende de lo que el significado de la palabra ''es'' es". Bueno, está bien, no realmente, pero depende de cuál sea el significado de la palabra "homoicónico". Este término es lo suficientemente controvertido que ya no decimos que Julia es homoicónica, por lo que puede decidir si califica. En lugar de tratar de definir la homoiconicidad, citaré lo que Kent Pitman (quien sabe una o dos cosas sobre Lisp) dijo en una entrevista con Slashdot en 2001:
Me gusta la disposición de Lisp para representarse a sí misma. La gente a menudo explica esto como su capacidad para representarse a sí misma, pero creo que eso está mal. La mayoría de los idiomas son capaces de representarse a sí mismos, pero simplemente no tienen la voluntad de hacerlo. Los programas Lisp están representados por listas y los programadores son conscientes de eso. No importaría si hubieran sido matrices. Es importante que la estructura del programa esté representada y no la sintaxis de los caracteres, pero más allá de eso, la elección es bastante arbitraria. No es importante que la representación sea la opción Right®. Es importante que sea una elección común y acordada para que pueda haber una comunidad rica de programas que manipulen programas que "negocien" en esta representación común.
Tampoco define la homoiconicidad, probablemente no quiera entrar en un argumento de definición más que yo. Pero acude al meollo de la cuestión: ¿qué tan dispuesto está el lenguaje a representarse a sí mismo? Lisp está dispuesto a hacerlo en extremo, ni siquiera puedes evitarlo: la representación del programa como datos se encuentra justo ahí, mirándote a la cara. Julia no usa la sintaxis de la expresión S, por lo que la representación del código como datos es menos obvia, pero no está muy oculta:
julia> ex = :(2a + b + 1)
:(2a + b + 1)
julia> dump(ex)
Expr
head: Symbol call
args: Array(Any,(4,))
1: Symbol +
2: Expr
head: Symbol call
args: Array(Any,(3,))
1: Symbol *
2: Int64 2
3: Symbol a
typ: Any
3: Symbol b
4: Int64 1
typ: Any
julia> Meta.show_sexpr(ex)
(:call, :+, (:call, :*, 2, :a), :b, 1)
julia> ex.args[3]
:b
julia> ex.args[3] = :(3b)
:(3b)
julia> ex
:(2a + 3b + 1)
El código de Julia está representado por el tipo Expr
(y los símbolos y los átomos), y aunque la correspondencia entre la sintaxis de la superficie y la estructura es menos obvia, sigue existiendo. Y, lo que es más importante, la gente sabe que el código es simplemente datos que pueden generarse y manipularse, por lo que existe una "rica comunidad de programas que manipulan programas", como dice KMP.
Esta no es solo una presentación superficial del código de Julia como una estructura de datos, así es como Julia representa su código para sí misma. Cuando ingresa una expresión en el REPL, se analiza en objetos Expr
. Esos objetos Expr
se pasan luego a eval
, lo que los "baja" a objetos Expr
algo más regulares, que luego se pasan a inferencia de tipo, todos implementados en Julia . El punto clave es que el compilador utiliza exactamente la misma representación de código que ve. La situación no es tan diferente en Lisp. Cuando observa el código Lisp, en realidad no ve los objetos de la lista, solo existen en la memoria de la computadora. Lo que ve es una representación textual de los literales de lista, que el intérprete de Lisp analiza y convierte en objetos de lista que luego combina, al igual que Julia. La sintaxis de Julia se puede ver como una representación textual para los literales Expr
: el Expr
resulta ser una estructura de datos algo menos general que una lista.
No conozco los detalles, pero sospecho que Elixir es similar, tal vez José intervendrá.
Ver también: