LISP - 作为返回值的函数
Lisp - 作为返回值的函数
Section titled “Lisp - 作为返回值的函数”在 Lisp 中,函数是一等公民(first-class citizens)。这意味着函数是一种数据类型,就像数字、字符串或列表一样。这一原则允许强大的编程范式,包括函数可以返回另一个函数作为其结果的能力。
一等函数具备以下能力:
- 可以存储在变量中:
(let ((my-func #'+)) ...) - 可以作为参数传递:
(mapcar #'1+ '(1 2 3)) - 可以从另一个函数返回:这是本章的重点。
一个接受另一个函数作为参数,或返回一个函数的函数,被称为高阶函数(higher-order function)。mapcar、reduce 和 remove-if 等函数是常见的内置高阶函数。一个返回函数的函数通常被称为函数工厂(function factory)。
当一个函数返回另一个函数时,返回的函数不仅包含代码;它还捕获其创建时的词法环境(lexical environment)。函数与其捕获的环境的这种组合被称为闭包(closure)。闭包“记住”了其创建作用域中的变量,即使外部函数执行完毕后也是如此。
示例:一个用于加法器的函数工厂
Section titled “示例:一个用于加法器的函数工厂”让我们创建一个高阶函数 make-adder,它充当一个工厂。它接受一个数字 n,并返回一个新函数(一个闭包),该函数将其自身参数加上 n。
main.lisp
Section titled “main.lisp”;; A higher-order function that returns a function.(defun make-adder (n) "This is a function factory. It creates and returns a new function that will add N to any number given to it." (lambda (y) (+ n y))) ; The returned lambda CLOSES OVER the variable 'n'.
;; --- Using the function factory ---
;; Create a specific "add-5" function.(let ((add-5 (make-adder 5)))
;; `add-5` is now a function we can call. ;; We use `funcall` to invoke a function stored in a variable. (print (funcall add-5 10)) ; -> 15 (print (funcall add-5 100)); -> 105)
;; We can create another adder on the fly.(let ((add-10 (make-adder 10))) (print (funcall add-10 10)) ; -> 20)当你执行这段代码时,它会返回以下结果:
1510520闭包的实际应用
Section titled “闭包的实际应用”- 可定制行为:你可以创建泛型函数并通过返回专门的版本来定制它们,减少代码重复。
- 有状态函数:闭包可用于在调用之间维护状态,无需使用全局变量或对象。一个经典示例是计数器函数,它会“记住”其上一个值。
- 延迟执行(回调):在事件驱动编程中(例如图形用户界面(GUI)或异步网络编程),你通常需要定义当事件发生时稍后应该发生什么。闭包非常适合创建这些回调函数,因为它们可以捕获必要的上下文,以便在事件最终触发时使用。
示例:一个有状态的计数器
Section titled “示例:一个有状态的计数器”(defun make-counter () (let ((count 0)) (lambda () (incf count)))) ; incf increments the 'count' variable
(let ((counter-a (make-counter)) (counter-b (make-counter)))
(print (funcall counter-a)) ; -> 1 (print (funcall counter-a)) ; -> 2
(print (funcall counter-b)) ; -> 1 (A separate closure with its own 'count') (print (funcall counter-a)) ; -> 3)每次调用 make-counter 都会创建一个新的闭包,拥有其自己的私有 count 变量,这展示了闭包如何封装行为和状态。