De acuerdo con este artículo, la siguiente línea de código Lisp imprime "Hola mundo" a la salida estándar.
(format t "hello, world")
Lisp, que es un lenguaje homoicónico , puede tratar el código como datos de esta manera:
Ahora imagine que escribimos la siguiente macro:
(defmacro backwards (expr) (reverse expr))
al revés es el nombre de la macro, que toma una expresión (representada como una lista) y la invierte. Aquí está "Hola, mundo" nuevamente, esta vez usando la macro:
(backwards ("hello, world" t format))
Cuando el compilador de Lisp ve esa línea de código, mira el primer átomo en la lista (
backwards
) y nota que nombra una macro. Pasa la lista no evaluada("hello, world" t format)
a la macro, que reorganiza la lista(format t "hello, world")
. La lista resultante reemplaza la expresión de macro, y es lo que se evaluará en tiempo de ejecución. El entorno Lisp verá que su primer átomo (format
) es una función, y lo evaluará, pasándole el resto de los argumentos.
En Lisp lograr esta tarea es fácil (corrígeme si me equivoco) porque el código se implementa como una lista (¿ s-expresiones ?)
Ahora eche un vistazo a este fragmento de OCaml (que no es un lenguaje homoicónico):
let print () =
let message = "Hello world" in
print_endline message
;;
Imagine que desea agregar homoiconicidad a OCaml, que utiliza una sintaxis mucho más compleja en comparación con Lisp. ¿Cómo lo harías tú? ¿El lenguaje tiene que tener una sintaxis particularmente fácil para lograr la homoiconicidad?
EDITAR : a partir de este tema encontré otra forma de lograr la homoiconicidad que es diferente de la de Lisp: la implementada en el lenguaje io . Puede responder parcialmente esta pregunta.
Aquí, comencemos con un bloque simple:
Io> plus := block(a, b, a + b) ==> method(a, b, a + b ) Io> plus call(2, 3) ==> 5
Bien, entonces el bloque funciona. El bloque más agregó dos números.
Ahora hagamos una introspección sobre este pequeño compañero.
Io> plus argumentNames ==> list("a", "b") Io> plus code ==> block(a, b, a +(b)) Io> plus message name ==> a Io> plus message next ==> +(b) Io> plus message next name ==> +
Molde caliente sagrado frío. No solo puede obtener los nombres de los parámetros de bloque. Y no solo puede obtener una cadena del código fuente completo del bloque. Puede colarse en el código y atravesar los mensajes dentro. Y lo más sorprendente de todo: es terriblemente fácil y natural. Fiel a la búsqueda de Io. El espejo de Ruby no puede ver nada de eso.
Pero, whoa whoa, hey ahora, no toques ese dial.
Io> plus message next setName("-") ==> -(b) Io> plus ==> method(a, b, a - b ) Io> plus call(2, 3) ==> -1