Как сделать так, чтобы программные конструкции 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, так что это всегда нужно учитывать. Как и в случае со специальными формами, действительно не так уж много изнурительных макросов, поэтому запомнить основные из них (базовые макросы потоков и условные макросы) очень просто.
Функции. Если это не одно из вышеперечисленных, это должна быть функция и следовать типичному синтаксису вызова функции.