LISP - 使用 `funcall` 调用函数
Lisp - 使用 funcall 进行动态函数调用
Section titled “Lisp - 使用 funcall 进行动态函数调用”在 Common Lisp 中,函数是一等公民。这意味着它们可以存储在变量中,作为参数传递给其他函数,并作为结果返回。funcall 函数是一个基本工具,允许你在运行时调用一个函数对象。这对于编写高阶函数和实现动态行为至关重要。
funcall 的语法
Section titled “funcall 的语法”(funcall function-designator arg1 arg2 ...)其中:
- function-designator:这是要调用的函数。它可以是一个命名函数的符号(例如 ’+、‘my-function)、一个lambda 表达式(一个匿名函数),或者一个函数对象本身。
- arg1、arg2、…:这些是要传递给指定函数的参数。
专业提示:要从一个名称获取函数对象,请使用特殊的 function 操作符,或其读取器宏(reader macro)的简写形式 #‘。例如,(function +) 与 #’+ 是相同的。
示例 1:调用命名函数
Section titled “示例 1:调用命名函数”你可以使用符号按名称动态调用函数。
main.lisp
Section titled “main.lisp”;;; Define a simple function(defun multiply-by-two (x) (* x 2))
;; Call a built-in function using its symbol name(print (funcall '+ 2 3))
;; Call our custom function using its symbol name(print (funcall 'multiply-by-two 5))执行代码会产生以下结果:
510示例 2:使用变量来保存函数
Section titled “示例 2:使用变量来保存函数”这展示了一等函数的强大之处,即要执行的操作可以在运行时决定。
main.lisp
Section titled “main.lisp”(defun multiply-by-two (x) (* x 2))(defun add-ten (x) (+ x 10))
;; Use LET to bind a function object to a local variable(let ((operation #'*)) (print (funcall operation 4 5))) ; Evaluates to 20
(let ((operation #'add-ten)) (print (funcall operation 6))) ; Evaluates to 162016示例 3:调用 Lambda 表达式
Section titled “示例 3:调用 Lambda 表达式”funcall 可以直接调用使用 lambda 创建的匿名函数。
main.lisp
Section titled “main.lisp”;; Call a lambda expression that multiplies two numbers(print (funcall #'(lambda (x y) (* x y)) 3 4))12示例 4:创建高阶函数
Section titled “示例 4:创建高阶函数”高阶函数是接受另一个函数作为参数的函数。funcall 使其易于实现。
main.lisp
Section titled “main.lisp”;; Define a higher-order function that applies an operation to two arguments(defun apply-operation (operation arg1 arg2) (funcall operation arg1 arg2))
;; Use the higher-order function with different operations(print (apply-operation #'+ 10 5))(print (apply-operation #'* 10 5))(print (apply-operation #'(lambda (a b) (- a b)) 10 5))15505调试和 funcall 与 apply 的比较
Section titled “调试和 funcall 与 apply 的比较”一个常见错误是尝试 funcall 一个未定义为函数的符号。Lisp 系统会发出 undefined-function 错误信号。
另外,请注意 apply 函数。它与 funcall 类似,但其最后一个参数必须是被调用函数的参数列表。
(funcall #'+ 1 2 3) ; 将 1, 2, 3 作为三个单独的参数传递(apply #'+ '(1 2 3)) ; 将列表 (1 2 3) 的元素作为参数传递
(apply #'+ 1 2 '(3 4)) ; apply 也可以接受前置参数- 动态分派:
funcall是当具体函数在运行时才知道时,调用函数的主要机制。 - 一等函数:
funcall完全体现了 Lisp 将函数作为数据处理的特性,从而实现了强大的函数式编程模式。 - 高阶函数:它是创建接受其他函数作为参数的函数的关键,也是现代软件设计的基石。