LISP - 作为参数的函数
Lisp - 函数作为一等公民
Section titled “Lisp - 函数作为一等公民”在 Lisp 中,函数是 一等公民。这是函数式编程的基石,意味着函数被视为与数字或字符串等其他任何数据类型一样。
- 可赋值给变量:函数可以存储在变量中。
- 可作为参数传递:函数可以作为参数传递给另一个函数。
- 可作为函数的返回值:函数可以作为另一个函数的返回值。
一个接受另一个函数作为参数或返回一个函数的函数称为高阶函数 (HOF)。此功能允许创建高度抽象和可重用的代码。Common Lisp 提供了许多内置的高阶函数,例如 mapcar、reduce、find-if 和 sort。
Lambda 表达式(匿名函数)
Section titled “Lambda 表达式(匿名函数)”lambda 表达式 创建一个匿名函数——一个没有名称的函数。这对于定义一个简单的、一次性使用的函数并将其作为参数传递给高阶函数非常有用,而无需使用 defun 正式定义它。
将函数作为参数传递
Section titled “将函数作为参数传递”要传递一个函数,我们必须引用函数对象本身,而不是它的名称。特殊操作符 #'( (function ...) 的简写)是实现此目的的标准方式。
示例:使用命名函数
Section titled “示例:使用命名函数”;; 一个接受函数和数字的高阶函数。(defun operate-on-five (op) (funcall op 5))
(defun square (x) (* x x))(defun cube (x) (* x x x))
;; 将 `square` 函数对象传递给 `operate-on-five`(format t "Square of 5 is ~d~%" (operate-on-five #'square))
;; 传递 `cube` 函数对象(format t "Cube of 5 is ~d~%" (operate-on-five #'cube))Square of 5 is 25Cube of 5 is 125这里,operate-on-five 是一个高阶函数。funcall 用于以参数 5 调用函数对象 op。
示例:使用 Lambda 表达式
Section titled “示例:使用 Lambda 表达式”mapcar 是一个经典的高阶函数,它将一个函数应用于列表的每个元素,返回一个包含结果的新列表。
;; `mapcar` 接受一个函数和一个或多个列表。(let ((numbers '(1 2 3 4)))
;; 使用 lambda 表达式动态定义一个函数 ;; 该函数将其参数加倍。 (let ((doubled (mapcar (lambda (x) (* x 2)) numbers))) (format t "Doubled list: ~a~%" doubled)))Doubled list: (2 4 6 8)funcall 与 apply
Section titled “funcall 与 apply”有两个重要的高阶函数用于动态调用函数:
funcall:用独立提供的参数调用函数。(funcall #'+ 1 2 3)apply:用一个列表作为参数来调用函数。(apply #'+ '(1 2 3))
(let ((args '(10 5))) ;; 使用 funcall,我们必须从列表中提取参数。 (format t "funcall: ~d~%" (funcall #'- (first args) (second args)))
;; 使用 apply,我们可以直接传递参数列表。 (format t "apply: ~d~%" (apply #'- args)))funcall: 5apply: 5为何重要:主要益处
Section titled “为何重要:主要益处”- 抽象和可重用性:高阶函数允许您编写用于映射、过滤和归约数据的通用函数,然后可以使用特定函数进行定制。例如,通过传递不同的谓词,一个单一的
filter函数可以用于查找偶数、长字符串或活跃用户。 - 清晰且富有表现力的代码:使用
mapcar和reduce等高阶函数通常会生成比手动编写循环更简洁、更具声明性的代码。 - 回调和事件处理:这是一种常见的模式,其中一个函数被注册(作为参数传递)以便在特定事件发生时(例如按钮点击或网络响应)被稍后调用。