[Scheme ]

Объявление функций

К этому моменту мы уже научились использовать функции, а также создавать свои собственные переменные, подошло время научиться создавать свои собственные функции.

Для этого давайте рассмотрим простой пример -- нам нужно найти площадь кольца с внешним радиусом 10 и внутренним радиусом 3, для этого нам нужно сначала вычислить площадь внешнего круга и дырки, а затем вычесть из площади внешнего круга площадь внутреннего круга (aka дырка). То есть нам нужно два раза вычислить площадь круга, но каждый раз с разными параметрами (аргументами), конечно, эти вычисления можно просто записать как:

(define pi 3.14159)
(- (* pi 10 10) (* pi 3 3))

->285.88469

Но лучше будет если мы создадим специальную функцию для вычисления площади круга:

(define (area-of-disk r) (* pi (* r r)))

В данном примере мы объявили новую функцию с именем "area-of-disk", которая вычисляет площадь круга, эта функция принимает один аргумент -- радиус круга, давайте теперь испытаем её:

(area-of-disk 5)

->78.53975

А теперь вычислим площадь нашего кольца:

(- (area-of-disk 10) (area-of-disk 3))

->285.88469

Функция "area-of-disk" является глобальной, так как она была объявленна с помощью "difine" для того чтобы объявлять местные функции нужно использовать один из макросов семейства "let".

А вот готовая функция, вычисляющаю площадь кольца:

(define (area-of-ring R r)
 (- (area-of-disk R) (area-of-disk r))
)
(area-of-ring 10 3)

->285.88469

Этот вариант использует глобальную функцию "area-of-ring".

(todo "добавить let и lambda")

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

Давайте рассмотрим следующий пример:

(define another+ +)
(another+ 1 2 3)

->6

В этом примере мы объявили глобальную переменную "another+" и присвоили ей в качестве значения функцию сложения.

(let ((another* *))
 (another* 8 2)
)

->16

А в этом примере мы объявили локальную переменную "another*" и присвоили её в качестве значения функцию умножения.

А вот ещё один интересный пример:

(define (fnc-arg fnc arg1 arg2) (fnc arg1 arg2))
(display (fnc-arg + 4 2))
(display (fnc-arg - 4 2))
(display (fnc-arg * 4 2))
(display (fnc-arg / 4 2))

->6
->2
->8
->2

В этом примере мы объявляем новую функцию, которая в качестве первого аргумента (fnc) принимает функцию, а затем применяет её к двум другим аргументам (arg1 и arg2).

lambda

С помощью макроса "lambda" можно создавать функции в любом месте кода, и даже без связывания их с переменными:

(lambda (arg1) (display arg1)(newline))

-><procedure /dev/stdin:1>

В этом примере мы просто создали безымянную функцию, которая нигде не была сохранена.

((lambda (arg1) (display arg1)(newline)) 12345)

->12345

А в этом примере мы не только создаём функцию, но и сразу её вызываем передавая ей в качестве аргумента "arg1" целое число 1234, которое она выводит на экран.

(let ((fnc (lambda (arg1 arg2)(+ arg1 arg2 1000000)) ))
 (display (fnc 1 2))
)
(display (fnc 10 20))

А в этом примере мы создаём локальную функцию, которая исчезает после завершения выполнения блока "let", именно поэтому мы и получаем ошибку "unbound location fnc".