Объявление функций
К этому моменту мы уже научились использовать функции, а также создавать свои собственные переменные, подошло время научиться создавать свои собственные функции.
Для этого давайте рассмотрим простой пример -- нам нужно найти площадь кольца с внешним радиусом 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".