Оформление кода Clojure

    Каждый раз принимаясь за изучение Clojure обращал внимание, что читать хорошо отформатированный код после некоторой тренировки становится легко. Но вот решать задачки из проекта эйлер, форматируя таким “правильным” образом код, для меня стало большой проблемой.
    Никаких разъяснений на русском я не нашёл, потому решил восполнить пробел переведя коротенькую инструкцию с английского.

    По сути своей код на Clojure – просто набор скобоклитералов, потому без грамотной расстановки отступов его тяжело читать. Clojure с расстановкой отступов выглядит примерно так:
    (defn my-zipmap [keys vals]
      (loop [map {}
             ks (seq keys)
             vs (seq vals)]
        (if (and ks vs)
            (recur (assoc map (first ks) (first vs))
                   (rest ks)
                   (rest vs))
          map)))
    (my-zipmap [:a :b :c] [1 2 3])
    


    Основное правило таково: продолжение списка на новые строки пишем с отступом. Так, строка начинающаяся с (loop имеет отступ в 2 пробела относительно строки (defn потому что список начинающийся с (loop – это непосредственный элемент списка начинающегося с (defn.
    Однако ниже автор кода отступает от основного правила, выравнивая строки (recur и (and, а не отступая 2 пробела от (if.
    Также вектор начинающийся с [map начинается внутри строки (не с новой строки) потому 2 следующие строки выравниваются по позиции следующей за [

    В результате правила таковы:
    1. Отделяем продолжения строки двумя пробелами если неприменимы следующие правила
    2. При возможности вместо отступа выравниваем открывающие скобки (, [ или {
    3. При продолжении внутреннего списка (списка начататого не с начала строки) выравниваем строки по первым символам элементов этого списка

    По сути, выравнивание всегда происходит относительно скобки (, [ или { к которой принадлежит выравниваемый элемент.
    Конечно без некоторой привычки читать и писать по такой схеме сложно.

    Для Lisp'ов типично обилие закрывающих скобок:

    (defn supply-arg [arg flist]
      (loop [flist flist cnter 0]
         (if (first flist) (do ((first flist) arg) 
                               (recur (rest flist) (+ 1 cnter)))))) 
    

    Справиться с ними, а так же расставить отступамы помогают текстовые редакторы заточенные под редактирование Clojure.

    Для начала всё. Есть смысл продолжать выкладывать статьи по Clojure?
    Отсюда: en.wikibooks.org/wiki/Learning_Clojure/Coding_Conventions
    Поделиться публикацией
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама
    Комментарии 22
    • +4
      > Каждый раз принимаясь за изучение Clojure…

      И много раз принимались? ;)

      Статьи по Clojure — да, имеет смысл. Но лучше по чём-нибудь более весомом, чем форматирование кода, тем более, если это просто перевод.
      • +2
        Пару раз принимался. Для меня актуальны самые азы, пока перевожу — сам вникаю. По мере роста буду переводить более серьёзные, конечно.
        • +4
          Только, пожалуйста, не превращайте это в цикл статей «Новичкам от новичков». Те, кто интересуется какой-то темой, берут книги и начинают систематично её изучать. А блог — он для каких-то отдельных интересных вещей. Для Clojure это может быть работа с отдельными фреймворками и библиотеками (Compojure, Ring, Incanter, Lazy XML), над отдельными задачами (natural language processing, vomputer vision, etc.), детальное рассмотрение каких-то фич (параллелизм, неизменяемые и ленивые структуры данных) и т.д.
          • 0
            Конечно не буду. Я восполняю пробел там где не нашёл литературы на русском. И так как опыта не много — перевёл, а не написал от себя.

            Ближайшая цель — простенький (но уже востребованный) веб-сервис, если не найду документации по какому-нибудь вопросу — станет следующим постом.
      • 0
        Как пользователь емакса, недоумеваю — разве clojure-mode не форматирует код за тебя?
        Продолжать несомненно стоит.
        • 0
          Emacs форматирует, другие редакторы — не всегда.
          • 0
            Eclipse тоже форматирует сам.
          • 0
            емакса я боюсьопасаюсь — это целый незнакомый мир для меня :)

            Полагаться на IDE с первых шагов как-то не хочется. Хочется понимания. Я же в Clojure хочу погрузиться не просто так, а после долгих лет плавания в чужом и своём PHP-быдлокоде. Хочется основательности:)
        • 0
          Меня вот очень смущает эта особенность — обилие закрывающих скобок в одной строке.
          • +2
            Когда люди их закрывают, рукой махают. Слева считают скобки, справа скобки ставят. В видео лекториума по по Scheme видно.
            • +1
              Закрыть их — не проблема, редакторы справляются. Но вот чисто визуально мне трудно понять, докуда блок тянется. Мне вот так было бы удобнее:
              (defn 
              	supply-arg
              	[arg flist]
                
              	(loop 
              		[flist flist cnter 0]
                  (if
              			(first flist) 
              			(do 
              				((first flist) arg) 
              				(recur (rest flist) (+ 1 cnter))
              			)
              		)
              	)
              ) 


              Привычка от С-like языков, видимо.
              • +3
                Ну так если много скобок закрывается разом, значит и много блоков соответственно блоки до этой тучи и тянутся. Получается как в питоне (?)
                • 0
                  > значит и много блоков соответственно блоки до этой тучи и тянутся
                  ага, вопрос — какие именно:)
                • +2
                  Границы блока определяются всё теми же отступами. Как в Python, например, только ещё со скобками.
                  • +3
                    Мне, как человеку, пишущему на лиспе на работе, хочется плакать от такой расстановки скобок и сдвигов.
                    • 0
                      Завидую вашей работе.
                • 0
                  В современных IDE это не проблема. Особенно с плагинами типа «rainbow parentheses» для Emacs'а. Т.е. разноцветные скобки.
                • +2
                  Вот есть вопрос — как нагляднее?
                  (when (= (somefunc param1 param2 param3) 1)
                    (...))

                  или
                  (when (= 1 (somefunc param1 param2 param3))
                    (...))
                  • +1
                    Мне легче читать второй вариант. Первый привычнее.
                    • +1
                      Когда начинал на Clo — пользовался первым вариантом — привычка от императивных языков. Но затем незметно для себя перешел на второй вариант.
                    • +1
                      Хороший стиль расстановки скобочек в лиспокоде устоялся десятилетия назад. Гораздо интереснее — подход к именованию типов, протоколов и конструкторов в Clojure, а также расширения типов и классов специнтерфейсами типа IFn. И вообще, правильное использование базовых интерфейсов языка.

                      Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.