Заболекарь
Мегакрендель: заколебарь, жаболекарь, зомболекарь, лежебокарь
Рассмотрим следующий код на языке hy:

(defn oy-fun [f]
  (print "oy function!")
  (f 1 2))

(defn vey-fun [n]
  (print "vey function!")
  (* n 2))

(defmacro oy-mac [f]
  (print "oy macro!")
  `(~f 1 2))

(defmacro vey-mac [n]
  (print "vey macro!")
  `(* ~n 2))

(print "functions returned:"
  (vey-fun (oy-fun +)))

(print "macros returned:"
  (vey-mac (oy-mac +)))



Сохраним его в function_vs_macro.hy и запустим:

hy function_vs_macro.hy



Результат:

vey macro!
oy macro!
oy function!
vey function!
functions returned: 6
macros returned: 6



Первые две строчки напечатаны на этапе компиляции, в чём легко убедиться, если сначала скомпилировать программу при помощи hyc в pyc-файл. А если этот pyc-файл исполнить потом обычным интерпретатором пайтона, то напечатаются остальные четыре. Ну, это в идеале так. На самом деле в генерации pyc-файлов для их последующего исполнения, когда я последний раз смотрел, был баг. Может, в той версии, что на гитхабе, уже починили, может, нет. В той версии, которую ставит pip, он ещё есть. Но это неважно.

Попробуем теперь воспроизвести то же поведение в кложуре. Берём ровно тот же код (только меняем print на println), запускаем при помощи lein exec...

oy function!
vey function!
functions returned: 6
vey macro!
oy macro!
macros returned: 6



Ык. Результат другой.

Никакой глубокой морали в этой истории нет. Просто lein exec и hy ведут себя по-разному. Если сравнивать с коммон лиспом и слаймом, то первый ведёт себя как C-x h C-c C-r, то есть выделить содержимое всего файла и скормить его eval, а второй как C-c C-k, то есть compile-file с последующим load. Чтобы добиться того поведения, которое нам нужно, нам придётся обернуть последние два println'а в функцию, как мы всё равно сделали бы, будь это обычный ляйнингеновский проект (но если это не проект, то её придётся, конечно, вызывать эксплицитно):

(defn -main [& args]
  (println "functions returned:"
    (vey-fun (oy-fun +)))

  (println "macros returned:"
    (vey-mac (oy-mac +))))



Мы можем и правда создать проект и запустить, скажем, lein uberjar, чтобы скомпилировать его в jar и убедиться, что первые две строчки действительно печатаются во время компиляции, а остальные четыре — только когда мы этот jar исполняем.

@темы: root@глупыйпингвин:~#