Почему этот код работает, хотя в нем нет открытой фигурной скобки

#clojure

#clojure

Вопрос:

Почему этот код работает?

 (defn g []
     do (println 10) (println 20))
  

Примечание: Нет ( перед do.

Ответ №1:

Теоретически это даже не должно компилироваться. Компилятор должен жаловаться, что do не может быть разрешен, поскольку это специальный символ не в первой позиции формы.

Это (вероятно, непреднамеренное) следствие использования одного и того же кода синтаксического анализа BodyExpr как для do специальной формы, так и для тела fn* специальной формы. При компиляции do специальной формы начальная do отбрасывается, а остальные формы компилируются. Использование этого же синтаксического анализатора для тела функции означает, что один голый do также может появиться первым.

 public static class BodyExpr implements Expr, MaybePrimitiveExpr{

    ...

    public Expr parse(C context, Object frms) {
        ISeq forms = (ISeq) frms;
        if(Util.equals(RT.first(forms), DO))
            forms = RT.next(forms);

    ....
  

Вы заметите, что если do повторяется, это

 (defn g [] do do (println 10) (println 20))
;=> CompilerException java.lang.RuntimeException: 
      Unable to resolve symbol: do in this context ...
  

не компилируется, как ожидалось.

Комментарии:

1. Спасибо. Итак, в нем явно закодировано исключение. Есть идеи, почему?

2. @Tim Смотрите редактирование. Это следствие (вероятно, непреднамеренное) использования одного и того же синтаксического анализатора как для do специальной формы, так и для тела функции special form, fn* .

3. Как странно… Я бы ожидал чего-то вроде: => ((fn [] println println)) ;; #<core$println clojure.core$println@15d3b17> , но это исключение, похоже, относится ко всем специальным формам. ((fn [] if)) например, выдает тот же RTE.