在Common Lisp中查找函数的arity

9

我一直在进行遗传编程,根据函数的arity将函数分成不同的函数集; 这是非常复杂的。

我想知道是否有更简单的方法来做到这一点。例如,是否有一个函数可以返回给定函数的arity。

提前致谢。


2
似乎是依赖于实现的。请参见https://groups.google.com/forum/#!msg/comp.lang.lisp/0WoivuykcKM/0SnbqcFyNogJ。 - Frédéric Hamidi
有一个非常接近的便携式库:https://github.com/Shinmera/trivial-arguments,但它返回完整的Lambda列表,而不是Arity。 - Ehvince
2个回答

15

对于解释函数,您应该能够使用function-lambda-expression

对于编译函数,不幸的是,这个函数通常返回nil,因此您将需要使用一个依赖于实现的函数(clocc/port/sys.lisp):

(defun arglist (fn)
  "Return the signature of the function."
  #+allegro (excl:arglist fn)
  #+clisp (sys::arglist fn)
  #+(or cmu scl)
  (let ((f (coerce fn 'function)))
    (typecase f
      (STANDARD-GENERIC-FUNCTION (pcl:generic-function-lambda-list f))
      (EVAL:INTERPRETED-FUNCTION (eval:interpreted-function-arglist f))
      (FUNCTION (values (read-from-string (kernel:%function-arglist f))))))
  #+cormanlisp (ccl:function-lambda-list
                (typecase fn (symbol (fdefinition fn)) (t fn)))
  #+gcl (let ((fn (etypecase fn
                    (symbol fn)
                    (function (si:compiled-function-name fn)))))
          (get fn 'si:debug))
  #+lispworks (lw:function-lambda-list fn)
  #+lucid (lcl:arglist fn)
  #+sbcl (sb-introspect:function-lambda-list fn)
  #-(or allegro clisp cmu cormanlisp gcl lispworks lucid sbcl scl)
  (error 'not-implemented :proc (list 'arglist fn)))

注意:在CL中,arity并不是一个真正的数字,因为Lisp函数除了必需参数外,还可以接受可选关键字剩余参数;这就是为什么上面的arglist函数返回参数函数的lambda列表而不是一个数字。
如果您只对仅接受必需参数的函数感兴趣,则需要使用类似以下内容的东西。
(defun arity (fn)
  (let ((arglist (arglist fn)))
    (if (intersection arglist lambda-list-keywords)
        (error "~S lambda list ~S contains keywords" fn arglist)
        (length arglist))))

谢谢,我刚刚发现我可以调用clisp自己的#'arglist,然后在返回的列表上进行成员搜索。 - Johnny McKenzie
1
这是一个很棒的答案,但也请检查下面“trivial-arguments”的答案!这个超轻量级库可以让你轻松、便携地调用(arglist fn)。 - Alberto
对于CCL,应该将ccl:arglist添加到上面的可移植arglist定义中(最好也在CLOCC中添加)。 - Torsten Anders

1

有一个便携式的库可以提供函数的lambda列表:https://github.com/Shinmera/trivial-arguments

(ql:quickload "trivial-arguments")

例子:

(arg:arglist #'gethash)
;; => (sb-impl::key hash-table &optional sb-impl::default)

(defun foo (a b c &optional d) nil)
(arglist #'foo)  ;; => (a b c &optional d)

它返回完整的 lambda 列表,包括 &optional 等内容,因此我们不能仅通过结果的长度来获取 arity。

很棒的库!一直在使用它进行一些便携式元编程!选择起来再也没有比这更容易的了。 - Alberto

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接