在lisp中从列表中评估函数

Pax*_*x0r 0 lisp functional-programming function list

我需要在lisp中编写一个带有两个参数的函数 - 无参数函数列表和整数列表.我需要按照第二个列表的顺序评估第一个列表中的函数,即(有趣的'(#'a#b#'c)'(2 0 1))应该评估c,a,b.我试过这样的功能:

(defun z4(funs kols)
    (funcall (nth (first kols) funs))
    (z4 funs (rest kols))
)
Run Code Online (Sandbox Code Playgroud)

但是在funcall我发现错误

NIL不属于CONS类型.

这是什么意思?通过简单地调用我得到同样的错误

(funcall (first funs))
Run Code Online (Sandbox Code Playgroud)

所以我认为它与从函数列表中获取函数有关.如何从函数列表中评估函数?

nam*_*ess 5

每次递归调用都会减少kols参数,直到变为参数nil.当kols成为nil你应终止递归,所以你应该添加测试的终止条件(即空列表):

(defun foo (funcs order)
  (unless (endp order)
    (funcall (nth (first order) funcs))
    (foo funcs (rest order))))
Run Code Online (Sandbox Code Playgroud)

我建议一个更易读的解决方案(因为ANSI Common Lisp Standard不强制实现执行尾调用优化,所以它也更优选):

(defun foo (funcs order)
  (loop for n in order do (funcall (nth n funcs))))
Run Code Online (Sandbox Code Playgroud)

在前面的示例中,我假设您为副作用运行函数,而不是返回值.


编辑1

正如Vatine所指出的那样,使用nth和列表来提供具有随机访问权限的集合对性能不利,因此将函数存储在vector(即一维array)rathen而不是列表中可能是值得的.因此,假设这funcs是一个vector函数,函数可以定义如下:

(defun foo (funcs order)
  (loop for n in order do (funcall (aref funcs n))))
Run Code Online (Sandbox Code Playgroud)

此外,我们可以代替arefsvref如果功能的阵列是simple vector(词汇表条目).前者更为通用,但后者在某些实现中可能更快.

可以simple vector使用其中任何一个创建函数

(vector #'func-a #'func-b ...)
Run Code Online (Sandbox Code Playgroud)

要么

#(func-a func-b ...)
Run Code Online (Sandbox Code Playgroud)

simple vector的功能都可以通过创建make-array函数为好,但仅当:adjustable:fill-pointer关键字参数未指定或nil.