From: Jacob West
Subject: Lisp Idiom for handling different argument types?
Date: 
Message-ID: <1144876405.995144.81770@e56g2000cwe.googlegroups.com>
I have a relatively simple question that I thought (the collective) you
might know the answer to:  what is the standard lisp idiom for writing
a single function that behaves differently for different input argument
types?
Take the following simple example:

(foo) => NIL
(foo 5) => 6
(foo '(1 2 3)) => 7
(foo 3.14) => 6.28

You get the point.  One function, variable behavior depending on input
type.  Obviously, there are many ways this can be handled, but my
question seeks the most "natural" lispy way to achieve this?

Thanks in advance.

From: Pascal Bourguignon
Subject: Re: Lisp Idiom for handling different argument types?
Date: 
Message-ID: <8764lejx5t.fsf@thalassa.informatimago.com>
"Jacob West" <··········@gmail.com> writes:

> I have a relatively simple question that I thought (the collective) you
> might know the answer to:  what is the standard lisp idiom for writing
> a single function that behaves differently for different input argument
> types?
> Take the following simple example:
>
> (foo) => NIL
> (foo 5) => 6
> (foo '(1 2 3)) => 7
> (foo 3.14) => 6.28
>
> You get the point.  One function, variable behavior depending on input
> type.  Obviously, there are many ways this can be handled, but my
> question seeks the most "natural" lispy way to achieve this?

To use the operator specially designed for this?

(defun foo (&optional (argument nil argument-p))
   (when argument-p
      (etypecase argument
          (integer  (1+ argument))
          (cons     (1+ (apply (function +) argument)))
          (real     (* 2 argument)))))

(mapcar (lambda (args) (apply (function foo) args))
        '(() (5) ((1 2 3)) (3.14)))
--> (NIL 6 7 6.28)

-- 
__Pascal Bourguignon__                     http://www.informatimago.com/

"You can tell the Lisp programmers.  They have pockets full of punch
 cards with close parentheses on them." --> http://tinyurl.com/8ubpf
From: Barry Margolin
Subject: Re: Lisp Idiom for handling different argument types?
Date: 
Message-ID: <barmar-D8AFA3.23594212042006@comcast.dca.giganews.com>
In article <··············@thalassa.informatimago.com>,
 Pascal Bourguignon <······@informatimago.com> wrote:

> "Jacob West" <··········@gmail.com> writes:
> 
> > I have a relatively simple question that I thought (the collective) you
> > might know the answer to:  what is the standard lisp idiom for writing
> > a single function that behaves differently for different input argument
> > types?
> > Take the following simple example:
> >
> > (foo) => NIL
> > (foo 5) => 6
> > (foo '(1 2 3)) => 7
> > (foo 3.14) => 6.28
> >
> > You get the point.  One function, variable behavior depending on input
> > type.  Obviously, there are many ways this can be handled, but my
> > question seeks the most "natural" lispy way to achieve this?
> 
> To use the operator specially designed for this?
> 
> (defun foo (&optional (argument nil argument-p))
>    (when argument-p
>       (etypecase argument
>           (integer  (1+ argument))
>           (cons     (1+ (apply (function +) argument)))
>           (real     (* 2 argument)))))
> 
> (mapcar (lambda (args) (apply (function foo) args))
>         '(() (5) ((1 2 3)) (3.14)))
> --> (NIL 6 7 6.28)

That's the traditional way.  The more modern way would use CLOS:

(defun foo (&optional argument)
  (generic-foo argument))

(defmethod generic-foo ((arg null))
  nil)
(defmethod generic-foo ((arg integer))
  (1+ argument))
(defmethod generic-foo ((arg cons))
  (1+ (apply #'+ arg)))
(defmethod generic-foo ((arg real))
  (* 2 arg))

This allows you to add new generic-foo methods when needed, without 
having to modify the original FOO function.

-- 
Barry Margolin, ······@alum.mit.edu
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***
*** PLEASE don't copy me on replies, I'll read them in the group ***
From: kavenchuk
Subject: Re: Lisp Idiom for handling different argument types?
Date: 
Message-ID: <1144931522.364696.326480@u72g2000cwu.googlegroups.com>
>From cltl2:

typecase is a conditional that chooses one of its clauses by examining
the __type__ of an object.

Macro defmethod...
A parameter specializer name is a symbol that names a __class__ or (eql
eql-specializer-form).

__type__ != __class__

(I was burnt not once :)

-- 
WBR, Yaroslav Kavenchuk.
From: Pascal Bourguignon
Subject: Re: Lisp Idiom for handling different argument types?
Date: 
Message-ID: <87u08ykpw2.fsf@thalassa.informatimago.com>
Barry Margolin <······@alum.mit.edu> writes:
> In article <··············@thalassa.informatimago.com>,
>  Pascal Bourguignon <······@informatimago.com> wrote:
>>> [...]
>> To use the operator specially designed for this?
>> 
>> (defun foo (&optional (argument nil argument-p))
>> [...etypecase...]
> That's the traditional way.  The more modern way would use CLOS:
>
> (defun foo (&optional argument)
>   (generic-foo argument))

You still need (perhaps) to distinguish (foo) from (foo nil).

> (defmethod generic-foo ((arg null))
>   nil)
> [...]
> This allows you to add new generic-foo methods when needed, without 
> having to modify the original FOO function.

-- 
__Pascal Bourguignon__                     http://www.informatimago.com/

"Specifications are for the weak and timid!"
From: Jacob West
Subject: Re: Lisp Idiom for handling different argument types?
Date: 
Message-ID: <1144910575.469984.5560@j33g2000cwa.googlegroups.com>
Thanks for the feedback guys.
From: Alan Crowe
Subject: Re: Lisp Idiom for handling different argument types?
Date: 
Message-ID: <86d5flbepc.fsf@cawtech.freeserve.co.uk>
Barry Margolin <······@alum.mit.edu> writes:

> In article <··············@thalassa.informatimago.com>,
>  Pascal Bourguignon <······@informatimago.com> wrote:
> 
> > "Jacob West" <··········@gmail.com> writes:
> > 
> > > I have a relatively simple question that I thought (the collective) you
> > > might know the answer to:  what is the standard lisp idiom for writing
> > > a single function that behaves differently for different input argument
> > > types?
> > > Take the following simple example:
> > >
> > > (foo) => NIL
> > > (foo 5) => 6
> > > (foo '(1 2 3)) => 7
> > > (foo 3.14) => 6.28
> > >
> > > You get the point.  One function, variable behavior depending on input
> > > type.  Obviously, there are many ways this can be handled, but my
> > > question seeks the most "natural" lispy way to achieve this?
> > 
> > To use the operator specially designed for this?
> > 
> > (defun foo (&optional (argument nil argument-p))
> >    (when argument-p
> >       (etypecase argument
> >           (integer  (1+ argument))
> >           (cons     (1+ (apply (function +) argument)))
> >           (real     (* 2 argument)))))
> > 
> > (mapcar (lambda (args) (apply (function foo) args))
> >         '(() (5) ((1 2 3)) (3.14)))
> > --> (NIL 6 7 6.28)
> 
> That's the traditional way.  The more modern way would use CLOS:
> 
> (defun foo (&optional argument)
>   (generic-foo argument))
> 
> (defmethod generic-foo ((arg null))
>   nil)
> (defmethod generic-foo ((arg integer))
>   (1+ argument))
> (defmethod generic-foo ((arg cons))
>   (1+ (apply #'+ arg)))
> (defmethod generic-foo ((arg real))
>   (* 2 arg))

However the types that you can use with defmethod are
deliberately and correctly restricted so that CLOS can
always tell which is the more specific class. One cannot do

CL-USER> (defun foo (x)
           (etypecase x
             ((cons (member + * / -) list) (eval x))
             ((integer 0 (10)) (digit-char x))))
FOO
CL-USER> (foo '(+ 2 2))
4
CL-USER> (foo (+ 2 2))
#\4

using defmethod alone.

Given my example, that might be considered a good thing :-)

Alan Crowe
Edinburgh
Scotland
From: Pascal Costanza
Subject: Re: Lisp Idiom for handling different argument types?
Date: 
Message-ID: <4a7eb6Fr80luU1@individual.net>
Alan Crowe wrote:
> Barry Margolin <······@alum.mit.edu> writes:
> 
> 
>>In article <··············@thalassa.informatimago.com>,
>> Pascal Bourguignon <······@informatimago.com> wrote:
>>
>>
>>>"Jacob West" <··········@gmail.com> writes:
>>>
>>>
>>>>I have a relatively simple question that I thought (the collective) you
>>>>might know the answer to:  what is the standard lisp idiom for writing
>>>>a single function that behaves differently for different input argument
>>>>types?
>>>>Take the following simple example:
>>>>
>>>>(foo) => NIL
>>>>(foo 5) => 6
>>>>(foo '(1 2 3)) => 7
>>>>(foo 3.14) => 6.28
>>>>
>>>>You get the point.  One function, variable behavior depending on input
>>>>type.  Obviously, there are many ways this can be handled, but my
>>>>question seeks the most "natural" lispy way to achieve this?
>>>
>>>To use the operator specially designed for this?
>>>
>>>(defun foo (&optional (argument nil argument-p))
>>>   (when argument-p
>>>      (etypecase argument
>>>          (integer  (1+ argument))
>>>          (cons     (1+ (apply (function +) argument)))
>>>          (real     (* 2 argument)))))
>>>
>>>(mapcar (lambda (args) (apply (function foo) args))
>>>        '(() (5) ((1 2 3)) (3.14)))
>>>--> (NIL 6 7 6.28)
>>
>>That's the traditional way.  The more modern way would use CLOS:
>>
>>(defun foo (&optional argument)
>>  (generic-foo argument))
>>
>>(defmethod generic-foo ((arg null))
>>  nil)
>>(defmethod generic-foo ((arg integer))
>>  (1+ argument))
>>(defmethod generic-foo ((arg cons))
>>  (1+ (apply #'+ arg)))
>>(defmethod generic-foo ((arg real))
>>  (* 2 arg))
> 
> 
> However the types that you can use with defmethod are
> deliberately and correctly restricted so that CLOS can
> always tell which is the more specific class. One cannot do
> 
> CL-USER> (defun foo (x)
>            (etypecase x
>              ((cons (member + * / -) list) (eval x))
>              ((integer 0 (10)) (digit-char x))))
> FOO
> CL-USER> (foo '(+ 2 2))
> 4
> CL-USER> (foo (+ 2 2))
> #\4
> 
> using defmethod alone.
> 
> Given my example, that might be considered a good thing :-)

In your example, the two sets of types are disjoint, so this could 
potentially work in CLOS. This would actually be a nice extension.


Pascal

-- 
3rd European Lisp Workshop
July 3-4 - Nantes, France - co-located with ECOOP 2006
http://lisp-ecoop06.bknr.net/