From: Benigno Uria
Subject: How to calculate the number of arguments a function takes. (its arity).
Date: 
Message-ID: <45ffffb1$1_1@filemon1.isp.telecable.es>
Hello,

Is there a portable way to calculate a function's arity in CL? I've 
skimmed the CLtL2 book without success. I suppose it can't be done 
because a function can take optional arguments... I'm I missing 
something obvious?

If there is no way... How would you approach that need?

I'm doing a genetic programming library and I want operators to be 
functions taking an unspecified number of arguments. I'd like to apply 
them this way:

(let ((operator (select-operator-from-weighted-list operators-list))
   (apply operator (select-n-individuals (arity-of operator)
                                         population)))

That would be the clean, desirable way. Unfortunately there is no 
arity-of function. :(

Right now I'm creating operators as subclasses of a CLOS class called 
operator which has an arity attribute. And the operator is implemented 
as a method taking an object of that class and the individuals as 
arguments. But it is ugly code.

I've also thought about implementing it as a macro which would add an 
'arity' property to the function's property list, but I've never used 
property lists. Would it be possible?

How would an experienced lisper approach this problem?

Thank you.

Benigno Ur�a.

From: Pedro Kroger
Subject: Re: How to calculate the number of arguments a function takes. (its arity).
Date: 
Message-ID: <1174405868.334546.175670@y80g2000hsf.googlegroups.com>
On Mar 20, 12:37 pm, Benigno Uria <·············@gmail...> wrote:

> Is there a portable way to calculate a function's arity in CL? I've
> skimmed the CLtL2 book without success. I suppose it can't be done
> because a function can take optional arguments... I'm I missing
> something obvious?

You could use the rest option:

(defun foo (&rest args)
  (length args))

(foo 1 2 3 4 5) => 5

Pedro Kroger
From: Lars Rune Nøstdal
Subject: Re: How to calculate the number of arguments a function takes. (its arity).
Date: 
Message-ID: <4600062e$0$29074$c83e3ef6@nn1-read.tele2.net>
On Tue, 20 Mar 2007 16:37:20 +0100, Benigno Uria wrote:

> Hello,
> 
> Is there a portable way to calculate a function's arity in CL? I've 
> skimmed the CLtL2 book without success. I suppose it can't be done 
> because a function can take optional arguments... I'm I missing 
> something obvious?
> 
> If there is no way... How would you approach that need?
> 
> I'm doing a genetic programming library and I want operators to be 
> functions taking an unspecified number of arguments. I'd like to apply 
> them this way:
> 
> (let ((operator (select-operator-from-weighted-list operators-list))
>    (apply operator (select-n-individuals (arity-of operator)
>                                          population)))

Maybe:


(defun genNumbers (n)
  (loop :for i :to (1- n) :collecting (random 100)))


(defun arity-of (operator)
  (get operator :arity))


(defun (setf arity-of) (arity operator)
  (setf (get operator :arity) arity))


(defmacro defOperator (name arglist &body body)
  `(progn
     (defun ,name ,arglist 
       ,@body)
    (setf (arity-of ',name) ,(length arglist))))


(defOperator plus (a b)
  (list a b (+ a b)))


(defun test ()
  (let ((operator 'plus))
    (apply operator (genNumbers (arity-of operator)))))


cl-user> (test)
(34 61 95)
cl-user> (test)
(12 77 89)

-- 
Lars Rune Nøstdal
http://nostdal.org/
From: Benigno Uria
Subject: Re: How to calculate the number of arguments a function takes. (its arity).
Date: 
Message-ID: <4600162f$1_4@filemon2.isp.telecable.es>
Lars Rune Nøstdal wrote:
> On Tue, 20 Mar 2007 16:37:20 +0100, Benigno Uria wrote:
> 
>> Hello,
>>
>> Is there a portable way to calculate a function's arity in CL? I've 
>> skimmed the CLtL2 book without success. I suppose it can't be done 
>> because a function can take optional arguments... I'm I missing 
>> something obvious?
>>
>> If there is no way... How would you approach that need?
>>
>> I'm doing a genetic programming library and I want operators to be 
>> functions taking an unspecified number of arguments. I'd like to apply 
>> them this way:
>>
>> (let ((operator (select-operator-from-weighted-list operators-list))
>>    (apply operator (select-n-individuals (arity-of operator)
>>                                          population)))
> 
> Maybe:
> 
> 
> (defun genNumbers (n)
>   (loop :for i :to (1- n) :collecting (random 100)))
> 
> 
> (defun arity-of (operator)
>   (get operator :arity))
> 
> 
> (defun (setf arity-of) (arity operator)
>   (setf (get operator :arity) arity))
> 
> 
> (defmacro defOperator (name arglist &body body)
>   `(progn
>      (defun ,name ,arglist 
>        ,@body)
>     (setf (arity-of ',name) ,(length arglist))))
> 
> 
> (defOperator plus (a b)
>   (list a b (+ a b)))
> 
> 
> (defun test ()
>   (let ((operator 'plus))
>     (apply operator (genNumbers (arity-of operator)))))
> 
> 
> cl-user> (test)
> (34 61 95)
> cl-user> (test)
> (12 77 89)
> 

Thank you, that is exactly what I was thinking of. I don't know why but 
I used to think property lists were messier, I now see they are nothing 
to have fear of.

Benigno Uría.
From: Alex Mizrahi
Subject: Re: How to calculate the number of arguments a function takes. (its arity).
Date: 
Message-ID: <4601005c$0$90273$14726298@news.sunsite.dk>
(message (Hello 'Benigno)
(you :wrote  :on '(Tue, 20 Mar 2007 18:13:18 +0100))
(

 ??>> (defmacro defOperator (name arglist &body body)
 ??>>   `(progn
 ??>>      (defun ,name ,arglist
 ??>>        ,@body)
 ??>>     (setf (arity-of ',name) ,(length arglist))))

 BU> Thank you, that is exactly what I was thinking of. I don't know why but
 BU> I used to think property lists were messier, I now see they are nothing
 BU> to have fear of.

if you would like to generate those operators on-fly without poluting global 
name space and inventing name, you can use something like

(defun %make-operator (lambda-expression)
  (let ((sym (gensym)) ;;this might be (make-symbol "dummy") as well
 (lambda-list (second lambda-expression)))
    (setf (symbol-function sym) lambda-expression
   (get sym :arity) (length lambda-list))
    sym))

(defun operator-arity (op) (get op :arity))

CL-USER> (defparameter *op* (%make-operator '(lambda (a b) (list a b (+ a 
b)))))
*OP*

CL-USER> *op*
#:G1035
CL-USER> (apply *op* '(3 4))
(3 4 7)

CL-USER> (operator-arity *op*)
2

and a bit of macro can make it a bit easier to use:

(defmacro make-operator ((&rest lambda-list) &body body)
  (list '%make-operator
 `'(lambda (,@lambda-list) ,@body)))

(defparameter *op* (make-operator (a b) (list a b (+ a b))))

note that it uses lambda-expression instead of closures, so actually there 
even no need for symbols at all -- you can pass around lambda-expressions 
and check their arity at any time as (length (second lambda-expression)). 
OTOH closures can be more efficient and they can be compiled.. you can 
compile lambda expression and bind it to symbol, if you'd like to.

)
(With-best-regards '(Alex Mizrahi) :aka 'killer_storm)
"�� ���� ������� �����") 
From: Benigno Uria
Subject: Re: How to calculate the number of arguments a function takes. (its arity).
Date: 
Message-ID: <46015b1e_3@filemon2.isp.telecable.es>
Alex Mizrahi wrote:

> [snip]
> if you would like to generate those operators on-fly without poluting global 
> name space and inventing name, you can use something like

Yes, I'll need to create higher-order functions returning a operators. 
For example:

(defun create-breeding-operator (brood-size fitness-function)
;;This lambda is the operator, I will need its arity afterwards
   (lambda (parent1 parent2)
     (select-2-best (create-n-children brood-size
                                       parent1
                                       parent2)
                    fitness-function)))

> 
> (defun %make-operator (lambda-expression)
>   (let ((sym (gensym)) ;;this might be (make-symbol "dummy") as well
>  (lambda-list (second lambda-expression)))
>     (setf (symbol-function sym) lambda-expression
>    (get sym :arity) (length lambda-list))
>     sym))
> 
> (defun operator-arity (op) (get op :arity))
> 
> CL-USER> (defparameter *op* (%make-operator '(lambda (a b) (list a b (+ a 
> b)))))
> *OP*

Your solution looks nice but I couldn't get it to work in SBCL 0.9.14:

The value (LAMBDA (A B) (LIST A B (+ A B))) is not of type FUNCTION.
[Condition of type TYPE-ERROR]

Trying to fix it and got to:

CL-USER> (defmacro make-operator ((&rest lambda-list) &body body)
	   `(let ((sym (gensym)))
	     (setf (symbol-function sym) (lambda ,lambda-list ,@body)
	           (get sym :arity) ,(length lambda-list))
	     sym))

CL-USER> (defun operator-arity (op) (get op :arity))
OPERATOR-ARITY

CL-USER> (defparameter *op* (make-operator (a b) (list a b (+ a b))))
*OP*

CL-USER> (funcall *op* 2 3)
(2 3 5)

CL-USER> (operator-arity *op*)
2

Is there anything wrong with my version?

I think it would solve the problem exposed on the example this way:

(defun create-breeding-operator (brood-size fitness-function)
;;"lambda" is substituted with "make-operator"
   (make-operator (parent1 parent2)
     (select-2-best (create-n-children brood-size
                                       parent1
                                       parent2)
                    fitness-function)))

> 
> [snip]
>
> 
> note that it uses lambda-expression instead of closures, so actually there 
> even no need for symbols at all -- you can pass around lambda-expressions 
> and check their arity at any time as (length (second lambda-expression)). 
> OTOH closures can be more efficient and they can be compiled.. you can 
> compile lambda expression and bind it to symbol, if you'd like to.
> 

As a Lisp newbie I don't fully understand your last paragraph. Aren't 
lambda-expressions compiled as the rest of a program? Or are you 
referring to lambda-expressions created during runtime? Or is it because 
  the lambda-expresions you created were qutoed? In that case wouldn't 
we need to eval them in order to call them?

Thank you,

Benigno Ur�a.
From: Alex Mizrahi
Subject: Re: How to calculate the number of arguments a function takes. (its arity).
Date: 
Message-ID: <46027abd$0$90268$14726298@news.sunsite.dk>
(message (Hello 'Benigno)
(you :wrote  :on '(Wed, 21 Mar 2007 17:19:41 +0100))
(

 BU> Trying to fix it and got to:

 BU> CL-USER> (defmacro make-operator ((&rest lambda-list) &body body)
 BU>     `(let ((sym (gensym)))
 BU>       (setf (symbol-function sym) (lambda ,lambda-list ,@body)
 BU>             (get sym :arity) ,(length lambda-list))
 BU>       sym))

ye, this way it works even much better -- it creates a lambda function that 
can be compiled, captures local variables into closure, etc.

 ??>> note that it uses lambda-expression instead of closures, so actually
 ??>> there even no need for symbols at all -- you can pass around
 ??>> lambda-expressions and check their arity at any time as (length
 ??>> (second lambda-expression)). OTOH closures can be more efficient and
 ??>> they can be compiled.. you can compile lambda expression and bind it
 ??>> to symbol, if you'd like to.
 ??>>
 BU> As a Lisp newbie I don't fully understand your last paragraph. Aren't
 BU> lambda-expressions compiled as the rest of a program?

---
lambda expression n. a list which can be used in place of a function name in 
certain contexts to denote a function by directly describing its behavior 
rather than indirectly by referring to the name of an established function; 
its name derives from the fact that its first element is the symbol lambda.
---

so it's just a list

 BU>  Or are you referring to lambda-expressions created during runtime? Or
 BU> is it because the lambda-expresions you created were qutoed?

yes, it's because it's quoted

 BU>  In that case wouldn't we need to eval them in order to call them?

i thought that APPLY should eat lambda-expressions directly, but it does 
not..

there are some ways to convert lambda-expression into a function -- (eval 
lambda-expression), (coerce lambda-expression 'function), (compile nil 
lambda-expression). looks like implementation i'm using automatically 
coerces lambda-expression into functions when setting symbol-function, but 
it's possible to do it explicitly to make my version working -- (setf 
(symbol-function sym) (coerce lambda-expression 'function)).

but a macro version that you've done appears to be superior -- it can be 
compiled etc.
even if you'd like to create new _code_ in runtime (not just stuff different 
parameters to existing), you can use EVAL with your macro.

)
(With-best-regards '(Alex Mizrahi) :aka 'killer_storm)
"?? ???? ??????? ?????") 
From: Benigno Uria
Subject: Re: How to calculate the number of arguments a function takes. (its arity).
Date: 
Message-ID: <460331e7$1_2@filemon1.isp.telecable.es>
Thank you for the explanation. I think I understand it now.

> 
> but a macro version that you've done appears to be superior -- it can be 
> compiled etc.
> even if you'd like to create new _code_ in runtime (not just stuff different 
> parameters to existing), you can use EVAL with your macro.
> 

I think I'll let the meta-gp to someone with more powerful computers. 
But I take note.

Thank you,

Benigno Ur�a
From: Alex Mizrahi
Subject: Re: How to calculate the number of arguments a function takes. (its arity).
Date: 
Message-ID: <4600fa98$0$90271$14726298@news.sunsite.dk>
(message (Hello 'Lars)
(you :wrote  :on '(20 Mar 2007 16:05:02 GMT))
(

 LRN> (defun genNumbers (n)
 LRN>   (loop :for i :to (1- n) :collecting (random 100)))

ehm, that looks a bit weird IMHO, (loop repeat n collect (random 100)) might 
be better

)
(With-best-regards '(Alex Mizrahi) :aka 'killer_storm)
"�� ���� ������� �����") 
From: Edi Weitz
Subject: Re: How to calculate the number of arguments a function takes. (its arity).
Date: 
Message-ID: <uhcsfap7g.fsf@agharta.de>
On Tue, 20 Mar 2007 16:37:20 +0100, Benigno Uria <·············@gmail...> wrote:

> Is there a portable way to calculate a function's arity in CL? I've
> skimmed the CLtL2 book without success. I suppose it can't be done
> because a function can take optional arguments... I'm I missing
> something obvious?

No, no portable way, but you could look at the source code of SLIME
and there at the definition of the ARGLIST function for the various
Lisps supported by SLIME.  All of them provide one way or another to
access the lambda list of a function.

HTH,
Edi.

-- 

Lisp is not dead, it just smells funny.

Real email: (replace (subseq ·········@agharta.de" 5) "edi")
From: Benigno Uria
Subject: Re: How to calculate the number of arguments a function takes. (its arity).
Date: 
Message-ID: <4600154b$1_2@filemon1.isp.telecable.es>
Edi Weitz wrote:
> On Tue, 20 Mar 2007 16:37:20 +0100, Benigno Uria <·············@gmail...> wrote:
> 
>> Is there a portable way to calculate a function's arity in CL? I've
>> skimmed the CLtL2 book without success. I suppose it can't be done
>> because a function can take optional arguments... I'm I missing
>> something obvious?
> 
> No, no portable way, but you could look at the source code of SLIME
> and there at the definition of the ARGLIST function for the various
> Lisps supported by SLIME.  All of them provide one way or another to
> access the lambda list of a function.
> 
> HTH,
> Edi.
> 

Thank you Edi. I'll take a look at it, but I think I'll take the option 
detailled by Lars Rune, I think it will keep my code cleaner and easier 
to test.

Anyway, being a Lisp newbie I'll take a look at SLIME code as I'm sure I 
can learn a great deal from it.

Benigno Ur�a.
From: Pascal Bourguignon
Subject: Re: How to calculate the number of arguments a function takes. (its arity).
Date: 
Message-ID: <87tzwdy8m9.fsf@voyager.informatimago.com>
Benigno Uria <·············@gmail...> writes:
> Is there a portable way to calculate a function's arity in CL? I've
> skimmed the CLtL2 book without success. I suppose it can't be done
> because a function can take optional arguments... I'm I missing
> something obvious?

Well, there is still _portable_ a way, something like the following,
using the condition system to find dynamically what the function
expects.

However, the level of portability may be fuzzy, because the exact
conditions signaled are not specified precisely enough by CLHS, and
type types specifiers you may get could also be implementation
dependant (AFAIK).  Also, the order in which errors are signaled is
not specified.  For example, the following function assumes that type
errors are given before number of argument errors.  But if a number of
argument error is given before, it won't work (it doesn't work on
SUBSEQ  in clisp for example).  It could be still written
independently of that (eg.  we could first pass different objects for
each argument, and use TYPE-ERROR-DATUM to identify the argument with
a bad type).

More difficult to do in a portable way of course would be to deal with
functions that have side effects.  In an implementation dependant way,
you could fork a subprocess where to botch the state.

And for the maximum number of arguments, indeed in general you might
have to go up to CALL-ARGUMENTS-LIMIT, which might be more than
available memory in some implementations. 



(defun minimal-function-arity (f)
  (let ((arguments '()))
    (labels ((something-of-type (type)
               (cond
                 ((subtypep type 'number) 1)
                 ((subtypep type 'string) "hi")
                 ((subtypep type 'vector)
                  ;; TODO: check the exected type of elements...
                  #(1))
                 ((subtypep type 'array)
                  ;; TODO: check the exected type of elements and dimensions...
                  #2A((1 2) (3 4)))
                 ((subtypep type 'null)    'nil)
                 ((subtypep type 'keyword) ':hi)
                 ((subtypep type 'symbol)  't)
                 ((subtypep type 'random-state) *random-state*)
                 ((subtypep type 'stream)       *terminal-io*)
                 ((subtypep type 'cons)     (cons nil nil))
                 ((subtypep type 'sequence) (list 1 2 3))
                 ((find-class type)
                  ;; TODO: We may loop and use MOP here to find the needed
                  ;;       arguments of make-instance
                  (make-instance type))
                 ;; ...
                 (t
                  (error "How do I make an instance of ~S" type))))
             
             (replace-last-argument-with-something-of-type (type)
               (setf (car (last arguments)) (something-of-type type)))
             (add-an-argument ()
               (setf arguments (nconc arguments (list 1)))))
      (loop :named search :do
         (handler-case
             (progn
               (apply f arguments)
               (return-from search (length arguments)))
           (type-error (err)
             (replace-last-argument-with-something-of-type
              (type-error-expected-type err)))
           (program-error (err)
             (add-an-argument))
           (error (err)
             (return-from search err)))))))


C/USER[95]> (mapcar 'minimal-function-arity (list (function +) 
                                                  (function sin)
                                                  (function truncate)
                                                  (lambda (a b c) (+ a b c))))
(0 1 1 3)





-- 
__Pascal Bourguignon__
http://www.informatimago.com
http://pjb.ogamita.org
From: Benigno Uria
Subject: Re: How to calculate the number of arguments a function takes. (its arity).
Date: 
Message-ID: <46033338$1_2@filemon1.isp.telecable.es>
Pascal Bourguignon wrote:
> Benigno Uria <·············@gmail...> writes:
>> Is there a portable way to calculate a function's arity in CL? I've
>> skimmed the CLtL2 book without success. I suppose it can't be done
>> because a function can take optional arguments... I'm I missing
>> something obvious?
> 
> Well, there is still _portable_ a way, something like the following,
> using the condition system to find dynamically what the function
> expects.
> 
> However, the level of portability may be fuzzy, because the exact
> conditions signaled are not specified precisely enough by CLHS, and
> type types specifiers you may get could also be implementation
> dependant (AFAIK).  Also, the order in which errors are signaled is
> not specified.  For example, the following function assumes that type
> errors are given before number of argument errors.  But if a number of
> argument error is given before, it won't work (it doesn't work on
> SUBSEQ  in clisp for example).  It could be still written
> independently of that (eg.  we could first pass different objects for
> each argument, and use TYPE-ERROR-DATUM to identify the argument with
> a bad type).
> 
> More difficult to do in a portable way of course would be to deal with
> functions that have side effects.  In an implementation dependant way,
> you could fork a subprocess where to botch the state.
> 
> And for the maximum number of arguments, indeed in general you might
> have to go up to CALL-ARGUMENTS-LIMIT, which might be more than
> available memory in some implementations. 
> 
> 
> 
> (defun minimal-function-arity (f)
>   (let ((arguments '()))
>     (labels ((something-of-type (type)
>                (cond
>                  ((subtypep type 'number) 1)
>                  ((subtypep type 'string) "hi")
>                  ((subtypep type 'vector)
>                   ;; TODO: check the exected type of elements...
>                   #(1))
>                  ((subtypep type 'array)
>                   ;; TODO: check the exected type of elements and dimensions...
>                   #2A((1 2) (3 4)))
>                  ((subtypep type 'null)    'nil)
>                  ((subtypep type 'keyword) ':hi)
>                  ((subtypep type 'symbol)  't)
>                  ((subtypep type 'random-state) *random-state*)
>                  ((subtypep type 'stream)       *terminal-io*)
>                  ((subtypep type 'cons)     (cons nil nil))
>                  ((subtypep type 'sequence) (list 1 2 3))
>                  ((find-class type)
>                   ;; TODO: We may loop and use MOP here to find the needed
>                   ;;       arguments of make-instance
>                   (make-instance type))
>                  ;; ...
>                  (t
>                   (error "How do I make an instance of ~S" type))))
>              
>              (replace-last-argument-with-something-of-type (type)
>                (setf (car (last arguments)) (something-of-type type)))
>              (add-an-argument ()
>                (setf arguments (nconc arguments (list 1)))))
>       (loop :named search :do
>          (handler-case
>              (progn
>                (apply f arguments)
>                (return-from search (length arguments)))
>            (type-error (err)
>              (replace-last-argument-with-something-of-type
>               (type-error-expected-type err)))
>            (program-error (err)
>              (add-an-argument))
>            (error (err)
>              (return-from search err)))))))
> 
> 
> C/USER[95]> (mapcar 'minimal-function-arity (list (function +) 
>                                                   (function sin)
>                                                   (function truncate)
>                                                   (lambda (a b c) (+ a b c))))
> (0 1 1 3)
> 

Nice approach. Not that I'm going to use it (I suppose the plist 
approach is more robust and offers better performance), but is a good 
example of using conditions nonetheless.

Thank you,

Benigno Ur�a