common-lisparityparameter-list

Find function's arity in Common Lisp


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.


Solution

  • 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))))