LISP - Calling Function using funcall
Lisp - Dynamic Function Calls with funcall
Section titled “Lisp - Dynamic Function Calls with funcall”In Common Lisp, functions are first-class citizens. This means they can be stored in variables, passed as arguments to other functions, and returned as results. The funcall function is a fundamental tool that allows you to invoke a function object that you have at runtime. This is essential for writing higher-order functions and implementing dynamic behavior.
Syntax of funcall
Section titled “Syntax of funcall”(funcall function-designator arg1 arg2 ...)Where:
function-designator: This is the function to be called. It can be a symbol that names a function (e.g.,'+,'my-function), a lambda expression (an anonymous function), or a function object itself.arg1,arg2, …: These are the arguments to be passed to the specified function.
Pro-Tip: To get a function object from a name, use the special function operator, or its reader macro shorthand #'. For example, (function +) is the same as #'+.
Example 1: Calling a Named Function
Section titled “Example 1: Calling a Named Function”You can use a symbol to dynamically call a function by its name.
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))Output
Section titled “Output”Executing the code produces the following result:
510Example 2: Using a Variable to Hold a Function
Section titled “Example 2: Using a Variable to Hold a Function”This demonstrates the power of first-class functions, where the operation to be performed can be decided at runtime.
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 16Output
Section titled “Output”2016Example 3: Calling a Lambda Expression
Section titled “Example 3: Calling a Lambda Expression”funcall can directly invoke an anonymous function created with lambda.
main.lisp
Section titled “main.lisp”;; Call a lambda expression that multiplies two numbers(print (funcall #'(lambda (x y) (* x y)) 3 4))Output
Section titled “Output”12Example 4: Creating a Higher-Order Function
Section titled “Example 4: Creating a Higher-Order Function”A higher-order function is a function that takes another function as an argument. funcall makes this easy to implement.
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))Output
Section titled “Output”15505Debugging and funcall vs. apply
Section titled “Debugging and funcall vs. apply”A common error is trying to funcall a symbol that is not defined as a function. The Lisp system will signal an undefined-function error.
Also, be aware of the apply function. It is similar to funcall, but its last argument must be a list of arguments for the function being called.
(funcall #'+ 1 2 3) ; Passes 1, 2, 3 as three separate arguments(apply #'+ '(1 2 3)) ; Passes the elements of the list (1 2 3) as arguments
(apply #'+ 1 2 '(3 4)) ; `apply` can also take leading argumentsKey Takeaways
Section titled “Key Takeaways”- Dynamic Dispatch:
funcallis the primary mechanism for invoking a function when the specific function is not known until runtime. - First-Class Functions:
funcallfully embraces Lisp’s treatment of functions as data, enabling powerful functional programming patterns. - Higher-Order Functions: It is the key to creating functions that accept other functions as arguments, a cornerstone of modern software design.