De acordo com este artigo, a seguinte linha de código Lisp imprime "Hello world" na saída padrão.
(format t "hello, world")
O Lisp, que é uma linguagem homoicônica , pode tratar o código como dados da seguinte maneira:
Agora imagine que escrevemos a seguinte macro:
(defmacro backwards (expr) (reverse expr))
para trás é o nome da macro, que pega uma expressão (representada como uma lista) e a inverte. Aqui está "Olá, mundo" novamente, desta vez usando a macro:
(backwards ("hello, world" t format))
Quando o compilador Lisp vê essa linha de código, ele olha para o primeiro átomo na lista (
backwards
) e percebe que ele nomeia uma macro. Ele passa a lista não avaliada("hello, world" t format)
para a macro, que reorganiza a lista para(format t "hello, world")
. A lista resultante substitui a expressão de macro e é o que será avaliado em tempo de execução. O ambiente Lisp verá que seu primeiro átomo (format
) é uma função e a avaliará, passando o restante dos argumentos.
No Lisp, é fácil realizar essa tarefa (corrija-me se estiver errado) porque o código é implementado como lista ( expressões-s ?).
Agora dê uma olhada neste trecho do OCaml (que não é uma linguagem homoicônica):
let print () =
let message = "Hello world" in
print_endline message
;;
Imagine que você deseja adicionar homoiconicidade ao OCaml, que usa uma sintaxe muito mais complexa em comparação com o Lisp. Como você faria isso? A linguagem precisa ter uma sintaxe particularmente fácil para alcançar a homoiconicidade?
EDIT : a partir deste tópico , encontrei outra maneira de obter homoiconicidade diferente da Lisp: a implementada na linguagem io . Pode parcialmente responder a esta pergunta.
Aqui, vamos começar com um bloco simples:
Io> plus := block(a, b, a + b) ==> method(a, b, a + b ) Io> plus call(2, 3) ==> 5
Ok, então o bloco funciona. O bloco positivo adicionou dois números.
Agora vamos fazer uma introspecção sobre esse pequeno companheiro.
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 frio santo quente. Você não pode apenas obter os nomes dos parâmetros do bloco. E você não apenas pode obter uma sequência do código fonte completo do bloco. Você pode se infiltrar no código e percorrer as mensagens dentro. E o mais surpreendente de tudo: é incrivelmente fácil e natural. Fiel à missão de Io. O espelho de Ruby não pode ver nada disso.
Mas, whoa whoa, ei agora, não toque nesse botão.
Io> plus message next setName("-") ==> -(b) Io> plus ==> method(a, b, a - b ) Io> plus call(2, 3) ==> -1