I've been doing some Genetic Programming and I've been separating functions into different function sets based on their arity; it's all rather complex.
I'd like to know if there's a simpler way to to do it. For example, if there's a function that returns the arity of a given function.
Cheers in advance.
For interpreted functions you should be able to use function-lambda-expression
.
For compiled functions, alas, this function often returns nil
, so you will have to use an implementation-dependent function (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)))
EDIT: note that arity in CL is not really a number, since Lisp functions can accept optional, rest and keyword arguments in addition to required ones; this is why the above arglist
function returns the lambda list of the argument function, not a number.
If you are only interested in functions which accept only required parameters, you would need to use something like
(defun arity (fn)
(let ((arglist (arglist fn)))
(if (intersection arglist lambda-list-keywords)
(error "~S lambda list ~S contains keywords" fn arglist)
(length arglist))))
There is a portable library that gives the function's lambda list: https://github.com/Shinmera/trivial-arguments
(ql:quickload "trivial-arguments")
Example:
(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)
It returns the full lambda list, with &optional
and stuff, so we can't just get the length
of the result for the arity.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With