Согласно этой статье следующая строка кода на Лиспе выводит «Hello world» на стандартный вывод.
(format t "hello, world")
Lisp, который является гомоиконическим языком , может обрабатывать код как данные следующим образом:
Теперь представьте, что мы написали следующий макрос:
(defmacro backwards (expr) (reverse expr))
в обратном направлении - это имя макроса, который принимает выражение (представленное в виде списка) и обращает его в обратном порядке. Вот снова «Hello, world», на этот раз с помощью макроса:
(backwards ("hello, world" t format))
Когда компилятор Lisp видит эту строку кода, он смотрит на первый атом в списке (
backwards
) и замечает, что он называет макрос. Он передает неоцененный список("hello, world" t format)
макросу, который переупорядочивает список(format t "hello, world")
. Результирующий список заменяет выражение макроса, и это то, что будет оцениваться во время выполнения. Окружение Lisp увидит, что его первый atom (format
) является функцией, и оценит его, передав ему остальные аргументы.
В Лиспе решить эту задачу легко (поправьте меня, если я ошибаюсь), потому что код реализован в виде списка ( s-выражения ?).
Теперь взгляните на этот фрагмент OCaml (который не является гомоиконическим):
let print () =
let message = "Hello world" in
print_endline message
;;
Представьте, что вы хотите добавить гомоконичность в OCaml, который использует гораздо более сложный синтаксис по сравнению с Lisp. Как бы Вы это сделали? Должен ли язык иметь особенно простой синтаксис, чтобы достичь гомоконичности?
РЕДАКТИРОВАТЬ : из этой темы я нашел другой способ достижения гомоконичности, отличающийся от Lisp: тот, который реализован на языке io . Это может частично ответить на этот вопрос.
Здесь давайте начнем с простого блока:
Io> plus := block(a, b, a + b) ==> method(a, b, a + b ) Io> plus call(2, 3) ==> 5
Итак, блок работает. Блок плюс добавил два числа.
Теперь давайте сделаем некоторый самоанализ этого маленького парня.
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 ==> +
Горячая святая холодная плесень. Вы можете не только получить названия параметров блока. И не только вы можете получить строку полного исходного кода блока. Вы можете проникнуть в код и просмотреть сообщения внутри. И самое удивительное: это ужасно просто и естественно. Верный для квеста Ио. Зеркало Руби не видит ничего из этого.
Но, воу, воу, эй, не трогай этот диск.
Io> plus message next setName("-") ==> -(b) Io> plus ==> method(a, b, a - b ) Io> plus call(2, 3) ==> -1