Scheme/Tutorial/2

Материал из ALT Linux Wiki

3 Имена

Выражение: (* 10 50) хорошо, а: (* width height) лучше. (* 3.1415926 10.5 10.5) — интригующе, а (* pi radius radius) — всё же понятнее, (+ 2/3 5/7) — какие-то невзрачные действия с дробями, а (+ my-piece-of-cake your-piece-of-cake) — уже обретает смысл.

Хочется сделать выражения более осмысленные и читаемые. Сказано — сделано. Фраза «Определим b как 5» записывается (define b 5). Сразу несколько примеров:

(define a 3)
(define b 4.5)		    ; b -- это действительное число 4,5
(define c 2/3)              ; c -- это рациональное число 2/3 (две третих)
(define str "some string")  ; str -- это строка "some string"
(define width (+ 2 5))      ; width -- это сумма 2 и 5, то есть width -- это 7

Если при определении встречается какое-либо выражение, например, сумма двух целых чисел из последнего примера, то это выражение вычисляется и переменная полагается равной уже его результату. Кстати, a,b,c,str и width действительно называются переменными. Вас это совершенно не должно смущать, ибо с переменными вы сталкивались ещё в курсе школьной алгебры. Итак, записать (define w (+ 1 3)) совершенно равносильно тому, что записать (define w 4). Либо вы подсчитаете в уме, либо за вас это сделает Scheme.

Ну уж коли мы вспомнили про школу, то теперь мы можем записать известные нам выражения.

(+ a b)               ; это a + b, где a и b -- какие-то переменные
(* 2 a)               ; это 2a, где a -- какая-то переменная
(* a a)               ; это квадрат a
(* c c c)             ; это куб c
(+ (* a a) (* b b))   ; это сумма квадратов a и b.

Теперь, вооружившись полученными знаниями, мы можем записывать уже гораздо более сложные программы на Scheme — например, такую:

(define width 3)
(define height 5)

(* width height)   ; умножить ширину на высоту

Наверное, вы заметили, что комментарии к коду я пишу, начиная их с ;. Это не случайно, все комментарии в тексте программы начинаются с символа ;. Когда интерпретатор или компилятор читает наш код, весь текст, начинающийся с ; и до конца строки он игнорирует.

Ещё одна программа:

(define pi 3.1415926)
(define radius 15)

(* pi radius radius)

4 Про истину

Если говорить кратко — «всё есть истина, кроме лжи», то есть

3 -- это истина
3.5 -- это истина
"test" -- это истина

Вообще все другие типы, которые мы ещё не изучили — это истина. Все, кроме «лжи», которая имеет обозначение #f.

Сразу познакомимся с простейшими логическими операциями: Результат (not 3) — это #f, Результат (not "test") — это тоже #f. Интересно, а какой должен быть результат (not #f) . Истин-то у нас много ;) На этот случай есть истина в первой инстанции, обозначаемая #t. Стало быть, результат (not #f) — это #t.

5 Разделяй и властвуй

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

Это очень важный и интересный момент в Схеме. Вы, наверное, часто замечали, что разделение многоэтапной операции на составляющие очень полезно. Например, создание нового процесса можно разделить на два этапа. Клонирование — fork и замена содержимого клона на другой процесс — exec. Такое разделение позволяет не запускать, например, новый процесс, когда это не нужно (сразу exec) или не порождать новый процесс, если клон сам справится с задачей (только fork).

Вот так и с функциями. Создание функции, например, f от одного аргумента, делится на собственно создание одноаргументной функции и на присваивании ей имени f.

Как присваивать имена, мы уже знаем — через define, а создание функции описывается следующей конструкцией:

(lambda (<аргументы>) <инструкции>)

Если аргументов нет, то они просто не пишутся. Результат вычисления последней инструкции возвращается в качестве ответа.

Примеры:

(lambda () (+ 2 5)) 
; создать безаргументную функцию, которая вернёт результат суммирования 2 и 5, то есть 7.
(lambda () 7)
;тоже самое, функция которая возвращает 7.
(lambda (x) (* x x))
;создать одноаргументную функцию от параметра x, которая вернёт результат
умножения x на x, то есть вернёт квадрат x.
(lambda (x y) (+ x y))
;создать двухаргументную функцию от параметра x, которая вернёт результат
сложения x и y.

Теперь совместим создание функции с присваиванием ей имени:

(define f (lambda() 7))
;f -- это функция без аргументов, которая возвращает 7
(define square (lambda (x) (* x x)))
;square -- это функция с одним аргуметном, которая возвращает квадрат переданного ей числа.
(define sum (lambda (x y) (+ x y)))
;sum -- это функция с двумя аргументами, которая возвращает сумму переданных ей двух чисел.

Вызываются созданные функции точно также, как мы это делали ранее: (имя аргументы) Как я говорил уже, синтаксис в Схеме очень регулярный, нет лишних синтаксических конструкций, если они не требуются.

Ну вот, теперь мы можем ещё больше усовершенствовать наши программы:

(define a 3)
(define b 5)
(define square (lambda (x) (* x x)))
(define sum (lambda (x y) (+ x y)))

(square 3)
;подсчитать квадрат числа 3, ответ будет 9.
(square a)
;подсчитать квадрат a, где a -- это 3, то есть ответ будет опять 9.
(sum 5 6)
;подсчитать сумму 5 и 6, ответ будет 11
(sum a 7)
;подсчитать сумму a и 7, ответ будет 10
(sum a b)
;подсчитать сумму a и b, ответ будет 8

далее>>