Ответ 1
В Racket (и других языках функционального программирования) lambda
очень полезны, если вы хотите передать встроенную функцию с одним выстрелом в качестве параметра, не определяя его в первую очередь. Например, предположим, что мы хотим скомпоновать список чисел. Мы можем пройти длинный путь и сначала определить функцию square
, а затем использовать map
:
(define (square x)
(* x x))
(map square '(1 2 3 4 5))
=> '(1 4 9 16 25)
... Или мы можем просто передать lambda
, например:
(map (lambda (x) (* x x))
'(1 2 3 4 5))
=> '(1 4 9 16 25)
Как вы можете видеть, существуют случаи, когда нам не нужно ссылаться на имя функции. Конечно, если процедура, представленная lambda
, будет повторно использована в нескольких частях или если она рекурсивна, тогда имеет смысл дать ей имя (так что оно уже не является анонимным):
(define square
(lambda (x) (* x x)))
Приведенное выше эквивалентно первому определению square
в начале. На самом деле, первое определение - это просто синтаксический сахар, чтобы определить функцию, но в конце все функции являются lambdas!
Теперь посмотрим на ваш пример. Здесь мы используем lambda
несколько иначе, а также иллюстрируем, почему они полезны - мы не только определяем функцию, но также возвращаем функцию:
(define test
(lambda (x)
(lambda (y)
(+ x y))))
Возможно, будет немного яснее, если мы напишем его так (это эквивалентно по причинам, упомянутым выше):
(define (test x)
(lambda (y)
(+ x y)))
Или даже короче - в Racket мы также можем использовать этот синтаксис для этой же цели:
(define ((test x) y)
(+ x y))
Это не то, что это лучший (или худший) способ определить функцию - это другое дело! мы определяем процедуру с именем test
, которая получает в качестве параметра x
и возвращает в результате новую анонимную функцию, которая, в свою очередь, получит в качестве параметра y
. Теперь в этих строках:
(define add27
(test 27))
... мы вызываем test
с x
значением 27
, который возвращает анонимную функцию, и мы называем эту функцию add27
. Помните lambda
, который был получен как параметр y
? теперь lambda
был назван add27
- и это пример currying. Подумайте об этом: test
- это функция, которая используется для генерации функций, которые добавляют фиксированное значение x
к заданному параметру y
, что объясняет, почему это работает:
(add27 2)
=> 29
С другой стороны, эта функция всегда добавляет 27
к своему параметру без возможности ее изменить:
(define (addTest x)
(+ x 27))
(addTest 2)
=> 29
Вы видите разницу? test
позволяет нам генерировать новые функции, которые добавляют произвольное значение, тогда как addTest
всегда добавляет фиксированное значение 27
. Что, если вы хотите добавить say, 100
? используя test
, это просто:
(define add100 (test 100))
Но addTest
нельзя изменить, нам нужно написать новую функцию:
(define (addTest100 x)
(+ x 100))
Я надеюсь, что это прояснит ситуацию, не стесняйтесь задавать в комментариях любые дополнительные вопросы о моем ответе.