Как сделать так, чтобы программные конструкции clojure было легче идентифицировать?

Clojure, будучи диалектом Lisp, унаследовал гомосиконичность Lisp. Гомойсоничность упрощает метапрограммирование, поскольку код можно обрабатывать как данные: отражение в языке (проверка сущностей программы во время выполнения) зависит от единой, однородной структуры и не требует обработки нескольких различных структур, которые появляются в сложном синтаксисе. [1].

Недостатком более однородной языковой структуры является то, что языковые конструкции, такие как циклы, вложенные if, вызовы функций или переключатели и т. Д., Больше похожи друг на друга.

В ближайшем будущем:

   ;; if:
   (if (chunked-seq? s)
     (chunk-cons (chunk-first s) (concat (chunk-rest s) y))
     (cons (first s) (concat (rest s) y)))

   ;; function call:
   (repaint (chunked-seq? s)
     (chunk-cons (chunk-first s) (concat (chunk-rest s) y))
     (cons (first s) (concat (rest s) y)))

Разница между двумя конструкциями - это просто слово. На негомойконическом языке:

// if:
if (chunked-seq?(s))
    chunk-cons(chunk-first(s), concat(chunk-rest(s), y));
else
   cons(first(s), concat(rest(s), y));

// function call:
repaint(chunked-seq?(s),
        chunk-cons(chunk-first(s), concat(chunk-rest(s), y)),
        cons(first(s), concat(rest(s), y));

Есть ли способ сделать эти программные конструкции легче идентифицировать (более заметными) в Clojure? Может быть, какой-то рекомендуемый формат кода или лучшие практики?

1 ответ

Помимо использования IDE, которая поддерживает подсветку синтаксиса для различных случаев, нет, на самом деле нет способа разграничить их в самом коде.

Вы можете попробовать использовать форматирование, чтобы различать вызовы функций и макросы:

(for [a b]
  [a a])

(some-func [a b] [a a])

Но тогда это мешает вам использовать однострочное понимание списка, используя for; иногда они могут аккуратно уместиться на одной линии. Это также не позволяет разбивать большие вызовы функций на несколько строк. Если функция сокращения не предопределена, большинство моих звонков reduce принять форму:

(reduce (fn [a b] ...)
        starting-acc
        coll)

Слишком много сценариев, чтобы попытаться ограничить форматирование вызовов. Как насчет более сложных макросов, таких как cond?

Я думаю, что ключевым моментом для понимания является то, что действие формы полностью зависит от первого символа в форме. Вместо того чтобы полагаться на специальные синтаксисы, чтобы различать их, приучите свои глаза к первому символу в форме и сделайте быстрый "поиск" в своей голове.

И действительно, есть только несколько случаев, которые необходимо рассмотреть:

  • Специальные формы, такие как if а также let (на самом деле let*). Это фундаментальные конструкции языка, поэтому вы будете подвергаться их постоянному воздействию.

    • Я не думаю, что это должно представлять проблему. Ваш мозг должен немедленно знать, что происходит, когда вы видите if, Существует так мало специальных форм, что простое запоминание - лучший путь.
  • Макросы с "необычным" поведением, такими как макросы потоков и cond, Есть еще несколько случаев, когда я буду просматривать чей-то код, и поскольку они используют макрос, с которым я не очень хорошо знаком, у меня уйдет секунда, чтобы выяснить поток кода.,

    • Однако это можно исправить, просто попрактиковавшись с макросом. Изучение нового макроса расширяет ваши возможности при написании Clojure, так что это всегда нужно учитывать. Как и в случае со специальными формами, действительно не так уж много изнурительных макросов, поэтому запомнить основные из них (базовые макросы потоков и условные макросы) очень просто.
  • Функции. Если это не одно из вышеперечисленных, это должна быть функция и следовать типичному синтаксису вызова функции.

Другие вопросы по тегам