Як написати читаний код Clojure?


13

Я новачок у Clojure. Я можу зрозуміти код, який я пишу, але пізніше це стає занадто важко зрозуміти.
Дуже складно узгодити дужки.

Яких загальних умовних положень слід дотримуватися щодо називання конвенцій та відступів у різних ситуаціях?

Наприклад, я написав зразок деструктуризації зразка, щоб зрозуміти, але це виглядає зовсім нечитабельним вдруге.

(defn f [{x :x y :y z :z [a b c] :coll}] (print x " " y  " " z " " a " " b " " c)) 

У разі деструктурування краще зробити це безпосередньо на рівні параметрів або запустити форму дозволу, а потім продовжити там?


3
Існує хороша відповідь про читабельність у Stack Overflow. Ви можете це перевірити. stackoverflow.com/a/1894891/1969106
yfklon

2
Писати читабельний код Lisp в цілому складно. Вони вигадали назви "Загублений у зайвій парентезі" не просто так.
Мейсон Уілер

Відповіді:


23

Названня конвенцій

  • залиште малі регістри для функцій
  • використовувати -для переносу (що було б підкресленням або випадом верблюда в інших мовах).

    (defn add-one [i] (inc i))

  • Предикати (тобто функції, що повертають істинні чи помилкові) закінчуються на ? Прикладах:odd? even? nil? empty?

  • Процедури зміни держави закінчуються !. Ви пам’ятаєте set!правильно? абоswap!

  • Виберіть короткі довжини назв змінних залежно від їх досяжності. Це означає, що якщо у вас дійсно невелика допоміжна змінна, ви часто можете просто використовувати однобуквене ім’я. (map (fn [[k v]] (inc v)) {:test 4 :blub 5})вибирайте більші імена змінних за потребою, особливо якщо вони використовуються для безлічі рядків коду, і ви не можете відразу вгадати їх призначення. (моя думка).

    Я відчуваю, що багато програмістів кложура, як правило, використовують загальні та короткі назви. Але це, звичайно, не дуже об’єктивне спостереження. Справа в тому, що багато функцій клоджура насправді є досить загальними.

    • Використовуйте значущі імена. Процедури щось роблять, для цього ви можете найкраще описати їх, використовуючи дієслова. Clojure вбудовані функції повинні поставити вас на правильному шляху: drop, take, assocі т.д. Тоді є хороша стаття , що описує способи вибору значуще ім'я: http://ecmendenhall.github.io/blog/blog/2013/09/ 02 / clean-clojure-смислові назви /

Функції лямбда

  • Фактично можна назвати лямбда-функції. Це зручно для налагодження та профілювання (мій досвід тут з ClojureScript).

    (fn square-em [[k v]] {k (* v v)})

  • Використовуйте вбудовані лямбда-функції #()як зручніше

Пробіл

  • Не повинно бути тільки парен-ліній. Тобто одразу закрийте дужки. Пам'ятайте, що паролі існують для редактора та компілятора, відступ призначений для вас.

  • Списки параметрів функцій переходять у новий рядок

   (defn мінуси
     [аб]
     (список ab))

Це має сенс, якщо ви думаєте про рядки doc. Вони знаходяться між назвою функції та параметрами. Наступний рядок doc, мабуть, не наймудріший;)

   (defn мінуси
     "Створення пари"
     [аб]
     (список ab))
  • Парні дані можна відокремити новим рядком, доки ви збережете спарювання
  (defn f 
    [{х: х 
      у: у 
      z: z  
      [abc]: coll}] 
    (друкуйте x "" y "" z "" a "" b "" c)) 

(Ви також можете вводити, ,як вам подобається, але це відчуває себе недоброзичливо).

  • Для відступу використовуйте досить хороший редактор. Роки тому це було emacs для редагування lisp, vim також чудово сьогодні. Звичайні ідентифікатори IDE також повинні забезпечувати цю функціональність. Просто не використовуйте випадковий редактор тексту.

    In vim в командному режимі ви можете використовувати =команду для правильного відступу.

  • Якщо команда стає занадто довгою (вкладена тощо), ви можете вставити новий рядок після першого аргументу. Тепер наступний код є досить безглуздим, але він ілюструє, як можна групувати та відступати вирази:

(+ (якщо-нехай [вік (: персональний вік)]
     (якщо (> 18 років)
       вік
       0))
   (кількість (діапазон (- 3 б)
                 (зменшити + 
                         (діапазон b 10)))))

Хороший відступ означає, що вам не доведеться рахувати дужки. Дужки призначені для комп'ютера (для інтерпретації вихідного коду та відступу). Відступ призначений для легкого розуміння.

Функції вищого порядку проти forта doseqформи

Виходячи з фону схеми, я був досить гордий, що зрозумів mapі лямбда-функції тощо. Тому досить часто я писав щось подібне

(map (fn [[k x]] (+ x (k data))) {:a 10 :b 20 :c 30})

Це досить важко читати. forФорма спосіб краще:

(for [[k x] {:a 10 :b 20 :c30}]
  (+ x (k data)))

`карта має багато застосувань і дуже приємна, якщо ви використовуєте названі функції. Тобто

(map inc [12 30 10]

(map count [[10 20 23] [1 2 3 4 5] (range 5)])

Використовуйте макроси для нитки

Використовуйте пронизують макроси ->і ->>так само , як dotoякщо це доречно.

Справа в тому, що макроси нарізки роблять вихідний код більш лінійним, ніж склад функції. Наступний фрагмент коду є досить нечитабельним без макросу потоків:

   (f (g (h 3) 10) [10 3 2 3])

порівняти з

   (-> 
     (h 3)
     (g 10)
     (f [10 3 2 3]))

Використовуючи макрос нарізки, зазвичай можна уникнути введення тимчасових змінних, які використовуються лише один раз.

Інші речі

  • Використовуйте docstrings
  • тримати функції короткими
  • читати інший код клоджура

Ця функція з деструктуруванням виглядає красиво з відступом!
Амо Талпалікар

+1 для коротких функцій. Багато маленьких функцій набагато більше
самодокументування

1
Я категорично не погоджуюся з тим, що корисно використовувати короткі імена змінних, навіть у функціях "короткого доступу". Хороші назви змінних є критичними для читабельності, і вони не коштують нічого, крім ключових штрихів. Це одна з речей, яка мене найбільше турбує щодо громади Clojure. Є багато людей, що мають майже ворожий опір описовим іменам змінних. Ядро Clojure всіяне 1-літерними іменами змінних для аргументів функції, і це набагато важче вивчити мову (наприклад, біг docабо sourceREPL). Кінець гніту, інакше чудова відповідь
Натан Уоллес

@NathanWallace Я певною мірою погоджуюся з вами, але в деяких аспектах я цього не роблю. Довгі імена іноді, як правило, роблять функції надвисокими. Таким чином, ви можете виявити, що деяка загальна робота фільтра насправді є загальною, тоді як, коли аргумент був applesзамість xs, ви вважали, що це стосується яблук. Тоді також я вважаю, що імена аргументів функції є більш значущими, ніж нехай скажімо, для змінної циклу. тому, якщо буде потреба, ви можете мати їх довше. В якості останньої думки: Я залишаю вас з «Ім'я код не дорожить» concatenative.org/wiki/view/Concatenative%20language / ...
wirrbel

Я можу додати абзац на щось на зразок приватного та загальнодоступного інтерфейсів. Особливо щодо бібліотек. Це аспект якості коду, про який говориться недостатньо, і я дізнався про це тонни з часу написання цієї відповіді.
wirrbel
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.