Управляющие Конструкции
Макро "if" работает следующим образом, вначале вычисляется "test-expression" если оно возвращает #t, то выполняется then-branch, в ином случае выполняется else-branch
(if test-expression then-branch else-branch)
Пример:
(if (> 2 1) (display "больше") (display "меньше"))
->больше
Else-branch я является необязательной и может быть опущенна, в случае если условие не выполняется ничего не будет сделанно.
(if (> 1 2) (display "больше"))
->
Макрос "when" работает анологично макросу "if" без else-branch
(when test-expression then-branch)
Пример:
(when (< 1 2) (display "меньше"))
->меньше
(when (> 1 2) (display "меньше"))
Макрос "unless" анологично макросу "when" с тем отличаем, что then-branch выполняется только в том случае, если test-expression возвращает #f.
(unless test-expression then-branch) (unless (> 1 2) (display "больше"))
->больше
Выражение:
(unless (not (> 1 2)) (display "больше"))
полностью анологично выражению:
(when (> 1 2) (display "больше"))
Макро "cond" позволяет работать сразу с несколькими условиями.
Например, давайте напишем функцию возвращающую знак числа, то есть если число положительное возвращается 1, если отрицательное -- "-1", а если равно нулю, то -- "0"
(define (my-sign x) (cond ((< x 0) -1) ((> x 0) 1) (else 0)))
В данном примере условие "else" будет выполняться в том случае если предыдущие условия не были выполнены.
А теперь давайте перейдём к решению квадратных уровнений.
;вначале мы определяем функцию, которая будет печатать найденые корни:
(define (display-root t r) (display t) (display " корень равен:") (display r) (newline)) ;затем определяем функцию для решения квадратного уравнения (define (get-roots a b c) (let ((d (- (* b b) (* 4 a c)))) ;здесь мы находим дискреминант (cond ;смотрим на количество корней ((< d 0) (display "корней нет")) ((= d 0) (display-root "единственный" (- (/ b (* 2 a))))) ((> d 0) ; два корня (display-root "первый" (/ (+ (- b) (sqrt d)) (* 2 a))) (display-root "второй" (/ (- (- b) (sqrt d)) (* 2 a))) ) ;> ) ;cond ) ;let (newline )
(get-roots -1 -2 15)
->
первый корень равен:-5.0
второй корень равен:3.0
Обратите внимание на то, что куски кода отвечающие за вычисление корней очень похожи:
первый: (/ (+ (- b) (sqrt d)) (* 2 a)))
второй: (/ (- (- b) (sqrt d)) (* 2 a)))
куски кода для нахождения двух корней отличаются друг от друга только используемой функцией -- "+" или "-", а код для нахождения единственного корня может быть представлен в следующем виде:
(/ (+ (- b) (sqrt d)) (* 2 a)))
Обратите внимание на то, что переменная d в этом случае всегда равна нулю.
Давайте определим локальную функцию для нахождения корней:
(lambda (op) (/ (op (- b) (sqrt d)) (* 2 a)))
Функция должна получать всего один аргумент -- "op", который должен быть функцией "+" или "-".
А теперь запишем новый вариант функции решающей квадратные уравнения:
(define (get-roots2 a b c) (letrec ( (d (- (* b b) (* 4 a c))) ;находим дискреминант (get-root (lambda (op) (/ (op (- b) (sqrt d)) (* 2 a))));функция вычисления корня ) (cond ((< d 0) (display "корней нет")) ((= d 0) (display-root "единственный" (get-root +))) ((> d 0) (display-root "первый" (get-root +)) (display-root "второй" (get-root -)) ) ;> ) ;cond ) ;let (newline) ) (get-roots2 -1 -2 15)
Обратите внимание, что в данном варианте мы использовали "letrec" вместо "let", так как определение функции "get-root" включает в себя переменные объявленные в том же самом блоке "letrec", а именно "d" (дискриминант).