Функции с переменным количеством аргументов
Мы уже рассмотрели как создавать свои функции, теперь мы рассмотрим процесс создания функций с переменным количеством аргументов.
Уже знакомая вам функция "area-of-disk" принимает один аргумент, если мы попытаемся вызвать её с другим количеством аргументов то мы получим ошибку:
(define (area-of-disk r) (* pi (* r r)))
->/dev/stdin:3:1: call to 'area-of-disk' has too few arguments (0; must be 1)
Давайте определим функцию для вычисления площади прямоугольника, если при вызове функции задаётся всего один аргумент, то возвращается площадь квадрата, а если два, то прямоугольника:
(define area-of-rect (case-lambda ((w) (* w w)) ((w h) (* w h )) ) ) (display "вызов функции с одним аргументом:") (display (area-of-rect 10)) (newline) (display "вызов функции с двумя аргументами:") (display (area-of-rect 10 20)) (newline)
Как вы видите, здесь мы используем специальную конструкцию "case-lambda":
(case-lambda ( (w);--первый набор аргументов (* w w);--код, который должен исполняться при одном аргументе ) ( (w h);--второй набор аргументов (* w h );--код, который должен исполняться при двух аргументах ) )
Давайте теперь напишем новый вариант функции "substring", который моожет принимать два или три параметра, если функция вызывается с тремя аргументами, то она должна работать как стандартная функция "substring", а если с двумя аргументами, то она должна возвращать подстроку представляющую из себя как бы "хвост" исходной строки, начинающийся с указанного в виде параметра индекса.
(define my-substring (case-lambda ((str start) (substring str start (string-length str))) ((str start end) (substring str start end)) ) )
Количество аргументов может быть достаточно велико и на момент создания функции может быть не известно точное количество аргументов, которые будут передаваться этой функции. В таких случаях можно использовать следующий синтаксис:
(define (arg1 arg2 ... arg3 . argList)
expr1 expr2 ...)
Давайте определим две функции использующие этот синтаксис и посмотрим как они работают:
(define (test0 . aList) (display aList) (newline)) (define (test1 a1 . aList) (display aList) (newline)) (define (test2 a1 a2 . aList) (display aList) (newline)) (define (test3 a1 a2 a3 . aList) (display aList) (newline)) (test0 1 2 3 4 5) (test1 1 2 3 4 5) (test2 1 2 3 4 5) (test3 1 2 3 4 5)
->(1 2 3 4 5)
->(2 3 4 5)
->(3 4 5)
->(4 5)
Как мы видим, в переменную aList помещаются те аргументы на которые не хватило обычных ... даже не знаю как их назвать, но вы, мои юные падаваны, и так всё прекрасно понимаете, что, куда и почему помещается, да?
Функции как аргументы
В отличие от некоторых других менее сознательных языков программирования, в Scheme функции можно совершенно безнаказанно передавать в качестве аргументов в функции и сохранять их в различных переменных.
(define (op f o1 o2) (f o1 o2))
(op + 4 2)
->6
(op - 4 2)
->2
(op * 4 2)
->8
(op / 4 2)
->2
(op max 4 2)
->4
Возврат функции из другой функции
А теперь ещё один пример, в данном примере одна функция будет возвращаться из другой функции.
(define (get-function funcName) (cond ((eq? funcName "plus") +) ((eq? funcName "minus") -) ((eq? funcName "mult") *) ((eq? funcName "div") /) ) ) (display ((get-function "plus") 4 2)) (newline) (display ((get-function "minus") 4 2)) (newline) (display ((get-function "mult") 4 2)) (newline) (display ((get-function "div") 4 2)) (newline)
->6
->2
->8
->2