Во многих языках для того, чтобы внутри вычисляемых выражений использовать логическое ветвление, приходится использовать отдельные специфические варианты конструкции if
(как это сделано в Python) или же вовсе — использовать отдельные тернарные операторы.
Здесь Lisp-подобные языки — и Clojure в частности — обладают одним важным преимуществом: в этих языках всё есть выражение. Поэтому отдельные варианты условных конструкций не нужны, вместо этого можно использовать if
, case
, cond
как часть любого другого выражения! Вот парочка примеров:
(println (if true "Ok" "Oops")) ; => Ok
(println (when false "Ok")) ; => nil
Заметьте, во втором случае условие для when
было ложным, поэтому всё выражение when
вычислилось в специальное "пустое" значение, но тем не менее — вычислилось! И функция println
вывела это значение на экран, пусть даже и в таком своеобразном виде.
Если помнить об этом свойстве языка, то можно писать довольно-таки сложные выражения, не выделяя промежуточные вычисления в переменные:
(defn classify [x]
(cond
(< x 0) "Negative"
(case x
(13 42 100500) true
false) "Special"
:else "Boring"))
В этом примере используются сильные стороны и cond
и case
: первый хорошо справляется с выбором по условию, а второй хорошо проверяет на совпадение с конкретными значениями, выступая при этом в качестве того самого условия для cond
.
И, раз уж речь зашла о выносе подвыражений в переменные, то тут у Clojure тоже всё хорошо. В других языках иной раз приходится делать присваивание значений переменным из условной конструкции или обходиться тернарным оператором. В Clojure же можно использовать обычный let
:
(defn classify [x]
(let [special?
(case x
(13 42 100500) true
false)]
(cond
(< x 0) "Negative"
special? "Special"
:else "Boring")))
Этот вариант читается лучше, чем предыдущий, но имеет один недостаток: значение
special?
вычисляется в любом случае, тогда как в предыдущем варианте его вычислять не нужно, если выполнилось условие, проверяющее аргумент на отрицательность.
Реализуйте функцию do-today
, которая принимает порядковый номер дня недели (целое число) в качестве аргумента и вычисляется в
"work"
для дней с понедельника (1
) по пятницу (5
),"rest"
для субботы (6
) и воскресенья (7
),"???"
для всех остальных значений, в том числе и для нечисловых!
Попробуйте использовать в решении различные комбинации if
, cond
и case
.Используйте функцию-предикат int?
чтобы проверить, что аргумент — целое число.
Если вы зашли в тупик, то самое время задать вопрос в «Обсуждениях». Как правильно задать вопрос:
Тесты устроены таким образом, что они проверяют решение разными способами и на разных данных. Часто решение работает с одними входными данными, но не работает с другими. Чтобы разобраться с этим моментом, изучите вкладку «Тесты» и внимательно посмотрите на вывод ошибок, в котором есть подсказки.
Это нормально 🙆, в программировании одну задачу можно выполнить множеством способов. Если ваш код прошел проверку, то он соответствует условиям задачи.
В редких случаях бывает, что решение подогнано под тесты, но это видно сразу.
Создавать обучающие материалы, понятные для всех без исключения, довольно сложно. Мы очень стараемся, но всегда есть что улучшать. Если вы встретили материал, который вам непонятен, опишите проблему в «Обсуждениях». Идеально, если вы сформулируете непонятные моменты в виде вопросов. Обычно нам нужно несколько дней для внесения правок.
Кстати, вы тоже можете участвовать в улучшении курсов: внизу есть ссылка на исходный код уроков, который можно править прямо из браузера.
Ваше упражнение проверяется по этим тестам
1(ns expressions-test
2 (:require [test-helper :refer [assert-solution]]
3 [index :refer [do-today]]))
4
5(assert-solution
6 [[1] [2] [3] [4] [5] [6] [7] [0] [-1] [10] [false] ["oops"]]
7 ["work" "work" "work" "work" "work" "rest" "rest" "???" "???" "???" "???" "???"]
8 do-today)
9
Решение учителя откроется через: