Во многих языках, для того чтобы внутри вычисляемых выражений использовать логическое ветвление, приходится использовать специфические варианты конструкции if
(как это сделано в Python) или же вовсе особые тернарные операторы.
Здесь лиспоподобные языки — и Racket в частности — обладают одним важным преимуществом: в этих языках всё есть выражение. Поэтому отдельные варианты условных конструкций не нужны, вместо этого можно использовать if
, case
, cond
как часть любого другого выражения! Вот парочка примеров:
(displayln (if #t "Ok" "Oops")) ; => Ok
(displayln (when #f "Ok")) ; => #<void>
Заметьте, во втором случае условие для when
было ложным, поэтому всё выражение when
вычислилось в специальное "пустое" значение, но тем не менее вычислилось! И функция displayln
вывела это значение на экран, пусть даже и в таком своеобразном виде.
Если помнить об этом свойстве языка, то можно писать довольно-таки сложные выражения, не выделяя промежуточные вычисления в переменные.
(define (classify x)
(cond
[(< x 0) "Negative"]
[(case x
[(13 42 100500) #t]
[else #f]) "Special"]
[else "Boring"]))
В этом примере используются сильные стороны cond
и case
: первый хорошо справляется с выбором по условию, а второй хорошо проверяет на совпадение с конкретными значениями, выступая при этом в качестве того самого условия для cond
.
И раз уж речь зашла о выносе подвыражений в переменные, то тут у Racket тоже всё хорошо. В других языках иной раз приходится делать присваивание значений переменным из условной конструкции или обходиться тернарным оператором. В Racket же можно использовать обычный let
:
(define (classify x)
(let ([is-special
(case x
[(13 42 100500) #t]
[else #f])])
(cond
[(< x 0) "Negative"]
[is-special "Special"]
[else "Boring"])))
Этот вариант читается лучше, чем предыдущий, но имеет один недостаток: значение
is-special
вычисляется в любом случае, тогда как в предыдущем варианте его вычислять не нужно, если выполнилось условие, проверяющее аргумент на отрицательность.
Реализуйте функцию do-today
, которая принимает порядковый номер дня недели (целое число) в качестве аргумента и вычисляется в:
"work"
для дней с понедельника (1
) по пятницу (5
),"rest"
для субботы (6
) и воскресенья (7
),"???"
для всех остальных значений, в том числе и для нечисловых!Попробуйте использовать в решении различные комбинации if
, cond
и case
.
Используйте функцию-предикат integer?
чтобы проверить, что аргумент — целое число.
Если вы зашли в тупик, то самое время задать вопрос в «Обсуждениях». Как правильно задать вопрос:
Тесты устроены таким образом, что они проверяют решение разными способами и на разных данных. Часто решение работает с одними входными данными, но не работает с другими. Чтобы разобраться с этим моментом, изучите вкладку «Тесты» и внимательно посмотрите на вывод ошибок, в котором есть подсказки.
Это нормально 🙆, в программировании одну задачу можно выполнить множеством способов. Если ваш код прошел проверку, то он соответствует условиям задачи.
В редких случаях бывает, что решение подогнано под тесты, но это видно сразу.
Создавать обучающие материалы, понятные для всех без исключения, довольно сложно. Мы очень стараемся, но всегда есть что улучшать. Если вы встретили материал, который вам непонятен, опишите проблему в «Обсуждениях». Идеально, если вы сформулируете непонятные моменты в виде вопросов. Обычно нам нужно несколько дней для внесения правок.
Кстати, вы тоже можете участвовать в улучшении курсов: внизу есть ссылка на исходный код уроков, который можно править прямо из браузера.
Ваше упражнение проверяется по этим тестам
1#lang racket
2
3(require (only-in rackunit check-equal? test-begin))
4(require "index.rkt")
5
6(test-begin
7 (check-equal? (do-today 1) "work")
8 (check-equal? (do-today 2) "work")
9 (check-equal? (do-today 3) "work")
10 (check-equal? (do-today 4) "work")
11 (check-equal? (do-today 5) "work")
12 (check-equal? (do-today 6) "rest")
13 (check-equal? (do-today 7) "rest")
14 (check-equal? (do-today 0) "???")
15 (check-equal? (do-today -1) "???")
16 (check-equal? (do-today 10) "???")
17 (check-equal? (do-today #f) "???")
18 (check-equal? (do-today "oops") "???"))
19
Решение учителя откроется через: