Бесплатный курс по Clojure. Зарегистрируйтесь для отслеживания прогресса →

Clojure: Объявление символов

Clojure — не является полностью функциональным языком программирования (Haskell, например, является), однако, это в большей степени продиктовано прагматичностью, которая заложена в дизайне языка. Благодаря этому, в Clojure можно оперировать как константами, так и переменными. Для начала, рассмотрим константы (создаются с помощью формы def):

(def id expr)
; id — идентификатор
; expr — выражение

; форма def 'связывает' идентификатор с выражением
(def lang "clojure")
(println lang) ; => clojure

Значением объявления может быть как нормальная форма (значение), так и составная:

(def result (+ 7 (- 4 6)))
(println result) ; => 5

def связывает имя (идентификатор) и значение следующего за ним выражения в рамках пространства имен, в котором происходит объявление. Имена объявлений, состоящие из нескольких слов, соединяют с помощью дефиса. В Lisp-языках повсеместно принят так называемый "kebab-case".

(def dangerous-year 1984)
(println dangerous-year) ; => 1984

Если же нужно работать с каким-либо изменяемым состоянием, тогда на помощь приходит форма atom с набором функций, благодаря которым атом можно менять:

(def lang (atom "clojure"))
(println @lang) ; => clojure

; мутируем lang
(reset! lang "Clojure!!!")
(println @lang) ; => "Clojure!!!

; объявим счетчик
(def counter (atom 0))

; поменяем его с помощью форм swap! и inc
(swap! counter inc) ; => 1
(swap! counter inc) ; => 2
; а теперь уменьшим счетчик на 1
(swap! counter dec) ; => 1

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

Заметим, что в данном случае мы тоже использовали форму def, почему так? Идея связывания (от англ. binding) является идиоматическим способом записать функцию, в которую передается аргументом то, что записано в связывании. Звучит немного запутанно, поэтому еще раз рассмотрим пример выше поподробнее:

(def          ; используем форму def
  lang        ; lang является идентификатором, с которым происходит связывание
  (atom       ; атом здесь является выражением, которое возвращает ссылку
    "clojure" ; данные, на которые ссылается атом 
  )
)

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

(def my-fn (fn [a] (inc a))) ; => свяжем идентификатор my-fn с анонимной функцией, в которой переданный аргумент увеличивается на 1
(my-fn 1) ; => 2
(my-fn 8) ; => 9

Задание

Создайте объявление, обозначающее "количество участников" (имя соорудите сами), присвойте ему значение 10 и распечатайте на экран.

Упражнение не проходит проверку — что делать? 😶

Если вы зашли в тупик, то самое время задать вопрос в «Обсуждениях». Как правильно задать вопрос:

  • Обязательно приложите вывод тестов, без него практически невозможно понять что не так, даже если вы покажете свой код. Программисты плохо исполняют код в голове, но по полученной ошибке почти всегда понятно, куда смотреть.
В моей среде код работает, а здесь нет 🤨

Тесты устроены таким образом, что они проверяют решение разными способами и на разных данных. Часто решение работает с одними входными данными, но не работает с другими. Чтобы разобраться с этим моментом, изучите вкладку «Тесты» и внимательно посмотрите на вывод ошибок, в котором есть подсказки.

Мой код отличается от решения учителя 🤔

Это нормально 🙆, в программировании одну задачу можно выполнить множеством способов. Если ваш код прошел проверку, то он соответствует условиям задачи.

В редких случаях бывает, что решение подогнано под тесты, но это видно сразу.

Прочитал урок — ничего не понятно 🙄

Создавать обучающие материалы, понятные для всех без исключения, довольно сложно. Мы очень стараемся, но всегда есть что улучшать. Если вы встретили материал, который вам непонятен, опишите проблему в «Обсуждениях». Идеально, если вы сформулируете непонятные моменты в виде вопросов. Обычно нам нужно несколько дней для внесения правок.

Кстати, вы тоже можете участвовать в улучшении курсов: внизу есть ссылка на исходный код уроков, который можно править прямо из браузера.

Полезное


Нашли ошибку? Есть что добавить? Пулреквесты приветствуются https://github.com/hexlet-basics
Если вы столкнулись с трудностями и не знаете, что делать, задайте вопрос в нашем большом и дружном сообществе