From: dave linenberg
Subject: CLOS method help needed
Date: 
Message-ID: <38924F53.6EC569FD@home.com>
    Using CLOS, I know it is quite common to restrict a method to
classes of a certain type for any pre-determined number of arguments.
    However, I am uncertain how this can be done with an   *unknown and
unlimited*  number of arguments, all of that certain type.

     I ask the question because I would like to make my own max method,
restricting it to a particular class type.
     (I also would simply like to know IF this can be done!!)

     The max function does this, taking any number of arguments, all of
them being of numeric type.
     (max 1 4 9 2  -1   )

    Is there a way to the same in CLOS?
    i.e. perhaps  something where I could restrict &rest to a particular
class such as ....

      (defmethod  max(   (&rest  myClasslist  myClass))
          (code to return max from myClasslist))

   (obviously the above is not valid code, but I am trying to make my
difficulties understood)

     (setf a (make-instance  'myClass))
     (setf b (make-instance 'myClass))
      etc

   such that the method
   (max  a b c d e f)

   *takes an unlimited and unknown number of  myClass arguments
   *checks to make sure that each argument  - a b c d e f - is in fact
of  myClass type
   *returns the correct object instance, using a common interface -  the
max function.

Thanks,
Dave Linenberg

From: Barry Margolin
Subject: Re: CLOS method help needed
Date: 
Message-ID: <Clrk4.54$7O6.1144@burlma1-snr2>
In article <·················@home.com>,
dave linenberg  <········@home.com> wrote:
>    Using CLOS, I know it is quite common to restrict a method to
>classes of a certain type for any pre-determined number of arguments.
>    However, I am uncertain how this can be done with an   *unknown and
>unlimited*  number of arguments, all of that certain type.

It can't.  CLOS only allows specialization on required arguments.

>     I ask the question because I would like to make my own max method,
>restricting it to a particular class type.

What you do is define a max-2 generic function that just takes two
arguments, and define methods specialized on your types.  Then define an
ordinary function max-many that takes an &rest argument and calls max-2:

(defmethod max-2 ((obj1 my-class) (obj2 my-class))
  ...)

(defun max-many (object obj1 &rest objects)
  (reduce #'max-2 objects :initial-value obj1))

-- 
Barry Margolin, ······@bbnplanet.com
GTE Internetworking, Powered by BBN, Burlington, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
From: dave linenberg
Subject: Re: CLOS method help needed
Date: 
Message-ID: <38932249.24FF883@home.com>
This is a multi-part message in MIME format.
--------------2908DB31DB9A077316054D12
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit

Barry Margolin wrote:

>What you do is .......

>(defmethod max-2 ((obj1 my-class) (obj2 my-class))   ...)

> (defun max-many (object obj1 &rest objects)
>   (reduce #'max-2 objects :initial-value obj1))

I thought I might have to do something like that (!!) , but I was hoping that I
could
do something more elgantly in CLOS.

In any case,   the reduce function is a predicate taking two arguments, which in
my case is not as quite as flexible as I would like.
I did notice upon further exploration (at least using my free Linux Allegro Lisp,
which I love :)  ) that
I could use  reduce with a lambda expression, such that I could use keywords.  (
or I could always
just write my own reduce function !!) .  Does the following code seem reasonable??
(I've just a Lisp
newbie)








--------------2908DB31DB9A077316054D12
Content-Type: text/plain; charset=us-ascii;
 name="daily-data.cl"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="daily-data.cl"

;; d.linenberg
;; daily-data.cl
;;
;; daily-data object

(defclass daily-data()
  ((name   :initform "unnamed":accessor daily-data-name)
   (date   :initform 19000101 :accessor daily-data-date)
   (open   :initform 0.00     :accessor daily-data-open)
   (high   :initform 0.00     :accessor daily-data-high)
   (low    :initform 0.00     :accessor daily-data-low)
   (close  :initform 0.00     :accessor daily-data-close)
   (volume :initform 0        :accessor daily-data-volume)
   (index  :initform -1       :accessor daily-data-index))) ;index of sequence if in a sequence

(defmethod print-object ((_daily-data daily-data) stream)
  (format stream "#<~S  name:~A  date:~A open:~A high:~A low:~A close:~A volume:~A index:~A>"
          (type-of           _daily-data)
          (daily-data-name   _daily-data)
          (daily-data-date   _daily-data)
	  (daily-data-open   _daily-data)
	  (daily-data-high   _daily-data)
	  (daily-data-low    _daily-data)
	  (daily-data-close  _daily-data)
	  (daily-data-volume _daily-data)
	  (daily-data-index  _daily-data)))

;; predicate w/key-word hlocv must eq 'high 'low 'open 'close 'volume
;; (note: might also want to add ability to change #'> function to #'< function
;; also in a key word so that function finds a max or a min)
(defmethod max-daily-data((obj1 daily-data) (obj2 daily-data) &key hlocv)
  (cond ((eq hlocv 'close) (if (> (daily-data-close obj1) (daily-data-close obj2))
			       obj1
			     obj2))
	((eq hlocv 'open) (if (> (daily-data-open obj1) (daily-data-open obj2))
				obj1
			      obj2))
	((eq hlocv 'low) (if (> (daily-data-low obj1) (daily-data-low obj2))
				obj1
			   obj2))
	((eq hlocv 'high) (if (> (daily-data-high obj1) (daily-data-high obj2))
			      obj1
			    obj2))
	((eq hlocv 'volume) (if (> (daily-data-volume obj1) (daily-data-volume obj2))
				obj1
			      obj2))
	(t nil)))
	

;; reduce normally takes a predicate which has only two arguments
;; we use a lambda expression in order to include a key-word for the predicate as well
;; we are forced to use the backwords quote in order to get the key-word value for
;; :hlocv into the lambda expression, thus we must use eval as well
(defun max-daily-data-sequence (data-sequence
				&key (start 0)
				     (end (1- (length data-sequence)))
				     (hlocv 'close))
  (eval `(reduce #'(lambda (obj1 obj2 &key hlocv)
	       (max-daily-data obj1 obj2 :hlocv ',hlocv)) ,data-sequence :start ,start :end ,end)))


;; test the max-daily-data-sequence function with
;; all data, 'open
;; all data, 'high
;; all data, 'low
;; data from index 0 through 1000, 'close
;; data from 800 throug 1000, 'volume
(defun test-daily-data ()
  (let ((data (subscribe-data *data-service* "IBM.PRN")))
    (print (max-daily-data-sequence data  :hlocv 'open)) 
    (print (max-daily-data-sequence data  :hlocv 'high)) 
    (print (max-daily-data-sequence data  :hlocv 'low))  
    (print (max-daily-data-sequence data  :end 1000 :hlocv 'close))
    (print (max-daily-data-sequence data :start 800 :end 1000 :hlocv 'volume))))

	



--------------2908DB31DB9A077316054D12--
From: Bernhard Pfahringer
Subject: Re: CLOS method help needed
Date: 
Message-ID: <86v48a$kjk$1@www.univie.ac.at>
In article <················@home.com>,
dave linenberg  <········@home.com> wrote:
>
>;; reduce normally takes a predicate which has only two arguments
>;; we use a lambda expression in order to include a key-word for the predicate as well
>;; we are forced to use the backwords quote in order to get the key-word value for
>;; :hlocv into the lambda expression, thus we must use eval as well
>(defun max-daily-data-sequence (data-sequence
>				&key (start 0)
>				     (end (1- (length data-sequence)))
>				     (hlocv 'close))
>  (eval `(reduce #'(lambda (obj1 obj2 &key hlocv)
>	       (max-daily-data obj1 obj2 :hlocv ',hlocv)) ,data-sequence :start ,start :end ,end)))
>
>

Hi, 
if I've understood the above correctly, the following would be
a preferable way of coding it:

(defun max-daily-data-sequence (data-sequence
			       &key (start 0)
				    (end (1- (length data-sequence)))
				    (hlocv 'close))
  (reduce #'(lambda (obj1 obj2)
	       (max-daily-data obj1 obj2 :hlocv hlocv))
          data-sequence :start start :end end))

Bernhard
-- 
--------------------------------------------------------------------------
Bernhard Pfahringer, OeFAI           http://www.ai.univie.ac.at/~bernhard/
--------------------------------------------------------------------------
  iSteve: i is iCeo in iApple. You'll be iified. iResistance is inVain.
From: dave linenberg
Subject: Re: CLOS method help needed
Date: 
Message-ID: <3893676B.F895F3F4@home.com>
Thanks for the tip, Bernhard!! That works.

I first tried *something* like that, but I was obviously
having a syntax problem and hacked the eval function call!

Dave



Bernhard Pfahringer wrote:

> Hi,
> if I've understood the above correctly, the following would be
> a preferable way of coding it:
>
> (defun max-daily-data-sequence (data-sequence
>                                &key (start 0)
>                                     (end (1- (length data-sequence)))
>                                     (hlocv 'close))
>   (reduce #'(lambda (obj1 obj2)
>                (max-daily-data obj1 obj2 :hlocv hlocv))
>           data-sequence :start start :end end))
>
> Bernhard
> --
> --------------------------------------------------------------------------
> Bernhard Pfahringer, OeFAI           http://www.ai.univie.ac.at/~bernhard/
> --------------------------------------------------------------------------
>   iSteve: i is iCeo in iApple. You'll be iified. iResistance is inVain.
From: Pierre R. Mai
Subject: Re: CLOS method help needed
Date: 
Message-ID: <87wvos4eoz.fsf@orion.dent.isdn.cs.tu-berlin.de>
dave linenberg <········@home.com> writes:

> In any case, the reduce function is a predicate taking two arguments,
> which in my case is not as quite as flexible as I would like.

Why use a generic function though?  Especially one that dispatches on
symbols to decide which accessors to use.  What future extensions are
you anticipating that the following function won't be able to handle?

(defun find-extreme 
    (sequence predicate &key (key #'identity) (start 0) end)
  "Finds and returns the object in `sequence' which is extremal with
regards to the given `predicate'.  The arguments `key', `start' and
`end' are treated as in all ANSI CL sequence functions.

Note that the (part of) the sequence denoted `start' and `end' must
not be empty."
  (unless (< start (or end (length sequence)))
    (error "Can't find the extreme of a sequence with no elements."))
  (reduce #'(lambda (a b)
              (if (funcall predicate (funcall key a) (funcall key b))
                  a
                  b))
          sequence :start start :end end))

(defun test-daily-data ()
  (let ((data (subscribe-data *data-service* "IBM.PRN")))
    (print (find-extreme data #'> :key #'daily-data-open))
    (print (find-extreme data #'> :key #'daily-data-high))
    (print (find-extreme data #'> :key #'daily-data-low))
    (print (find-extreme data #'> :key #'daily-data-close :end 1000))
    (print (find-extreme data #'> :key #'daily-data-volume 
                         :start 800 :end 1000))))

You can use this function together with either generic accessors
or even with a generic function predicate, should this be useful:

(defmethod valuation ((obj daily-data))
  (daily-data-close obj))

(defmethod valuation ((obj strange-thing))
  ;; Do strange stuff to determine the valuation of strange-thing
  ...)

(defun get-minimum-asset (asset-data)
  (find-extreme #'< :key #'valuation asset-data))

(defmethod max-value ((a daily-data) (b something-strange))
  ;; Do strange stuff to determine the bigger valuation of the two
  ;; things...
  (if foobar a b))

(defmethod max-value ((b something-strange) (a daily-data))
  ;; Do even stranger stuff ...
  (if barfoo a b))

etc.

(defun get-max-value-asset (asset-data)
  (find-extreme #'max-value asset-data))

Regs, Pierre.

-- 
Pierre Mai <····@acm.org>         PGP and GPG keys at your nearest Keyserver
  "One smaller motivation which, in part, stems from altruism is Microsoft-
   bashing." [Microsoft memo, see http://www.opensource.org/halloween1.html]
From: ········@my-deja.com
Subject: Re: CLOS method help needed
Date: 
Message-ID: <8749n4$l95$1@nnrp1.deja.com>
Pierre R. Mai wrote:

> Why use a generic function though?  Especially one that dispatches on
> symbols to decide which accessors to use.  What future extensions are
> you anticipating that the following function won't be able to handle?

I never even thought of dispatching on the symbol itself, even though it
may seem the most obvious (and most elegant) solution. It really cleans
up the code, eliminates those ugly conditionals and is much more
extensible.

Thanks to all who have helped,
Dave Linenberg


Sent via Deja.com http://www.deja.com/
Before you buy.