[Scheme ]

Управляющие Конструкции

Макро "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" (дискриминант).