From: Shy Shyman
Subject: How to touch struct slots
Date: 
Message-ID: <848jvu$8lq@news.or.intel.com>
Hi there,

I need to create a struct when one of the slots should be a function object.
I want this function to have access to other slots in the same instance of
the struct - This is somthing like 'this' in C++:

(defstruct
 (new-object
   (:include old-object
   (body nil)
   (program #'startegy)
  )
 )
)

Then I want to be able to refer to the body slot in the 'startegy function

(DEFUN 'startegy (arg)
    (cond
            "this->" body ...


)


If I can't do it with defstruct  is there a way to do this with defclass


Thanks  in advance
and Happy new year

Shy

From: Barry Margolin
Subject: Re: How to touch struct slots
Date: 
Message-ID: <rYQ94.38$vN2.1097@burlma1-snr2>
In article <··········@news.or.intel.com>,
Shy Shyman <··········@intel.com> wrote:
>Hi there,
>
>I need to create a struct when one of the slots should be a function object.
>I want this function to have access to other slots in the same instance of
>the struct - This is somthing like 'this' in C++:
>
>(defstruct
> (new-object
>   (:include old-object
>   (body nil)
>   (program #'startegy)
>  )
> )
>)
>
>Then I want to be able to refer to the body slot in the 'startegy function
>
>(DEFUN 'startegy (arg)
>    (cond
>            "this->" body ...
>
>
>)

The program has to accept the object as a parameter, and you would have to
require that the caller pass the object as an argument explicitly.  You can
automate this by supplying a function that does it:

(defun call-program (object &rest arguments)
  (apply (new-object-program obj) obj arguments))

The startegy function would be written as:

(defun startegy (object arg)
  ...
  (do-something-with (new-object-body object))
  ...)

>If I can't do it with defstruct  is there a way to do this with defclass

Since CLOS isn't based on message passing, there's no implicit "this" in
it.  All objects are passed explicitly.  So the solution using CLOS would
look very similar to the solution using DEFSTRUCT.

-- 
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: Tim Bradshaw
Subject: Re: How to touch struct slots
Date: 
Message-ID: <ey3n1qwavmo.fsf@cley.com>
* Shy Shyman wrote:
> Hi there,
> I need to create a struct when one of the slots should be a function object.
> I want this function to have access to other slots in the same instance of
> the struct - This is somthing like 'this' in C++:

> (defstruct
>  (new-object
>    (:include old-object
>    (body nil)
>    (program #'startegy)
>   )
>  )
> )

I'm not quite sure what you are trying to do here.  If you want to
have a function which implements per-class behaviour, you'd typically
do that with a method:

	
    (defstruct (foo (:include ...))
     ...)

    (defmethod startegy ((this foo) ...)
      ...)

If you want the function in a slot, then presumably the behaviour you
want is finer-grained than per-class -- so the function might vary
per-instance somehow -- or perhaps close over state which is only
known at instance-creation time.

In that case I think you'd just want to arrange to call it with an
extra argument:

    (defun call-foo-fn (foo &rest args)
      (apply (foo-program foo) foo args))


--tim
From: ArolAmbler
Subject: Re: How to touch struct slots
Date: 
Message-ID: <20000109075014.12489.00000590@nso-fa.aol.com>
You MAY want to use a closure.  

(defun  make-thingy ( slot1 slot2 )

  #'(lambda (arg)
          (if (integerp arg1) 
                 (prog1 slot1 (setq slot1 arg1))
                 (prog2 (incf slot1) slot2 (setq slot2 arg))
   )      )
)

or you may want to have a closure inside a structure slot.

The above example has the following behavior:

Each time make-thingy is called, with 2 arguments, it returns
a "closure" (a function), that remembers the two arguments passed
to make-thingy.

The closure, when invoked with one argument, decides
if the argument is an integer or not.
  If it is, it retruns the current value of slot1, but also alters
     slot1 so it contains the integer that was passed.

  If the argument is not an integer,  
            it adds 1 to slot1's value,
            returns whatever is currently in slot2, 
and     alters slot2 to now contain whatever was passed as the
            argument.

So, overall, this is a kind of 1 stage delay pipeline, that also
counts how often is it used to delay, and the counter is resetable
when it is read.

This is ONE of the idioms that lisp uses that is "similar" to a c++
class.  But, unlike c++, the object is truely "sealed up", and only the
debugger can typically get at the innards of the closure.  Further,
there can be arrays of closures, or other things.

One of the STANDARD lisp tricks goes by the name of Currying. (I believe after
Wm. Curry, but that may be wrong).

(defun reg-exp-compile (reg-exp)
   (let ( (digested (do-digest reg-exp)) )
     #'(lambda (string)   
              (run-it digested string)
        )
)

Above is a typical example: the reg-exp-compile function takes
a regular expression, does some fancy analysis on it (represented
by the function do-digest, and puts the results of this "compilation"
into the variable "digested".  Then a closure is returned.

Now a closure is just an ordinry function.  In this case, it takes an
argument, and calls a run-time function that can do te regular
expression pattern match faster, because it has the predigested
regular expression to work with.

A less esoteric application:

(defun adder (arg1)
    (cond
       ( (= arg1 0)  #'identity
       ((= arg1 1)   #'1+
       ((= arg1 -1)  #'1-
       (t      #'(lambda (n) (+ arg1 n))   )
)   )

When adder is called, with one argument, it makes a few quick tests:
for 0, 1, and -1.  In those cases, it returns a specialized one argument
function.
Otherwise, it returns a general one argument function that adds the
argument given to adder to the argument given to the function adder
returns.

Although it stretches credulity to believe, in this case,  any performance
benefit can be gotten from adder, it certainly is worth noting that
if there is a function of more than one argument, that can do much
of is work withouth knowing all of the arguements, Currying may
be helpful.  This is particularly true if there are many calls to the function,
and there are many different fast arguments for the "slow"
arguments.  They need not, necessarily, arrive in a "nice" order:
the Curried functions can be cached, and the "right" one used 
when needed.

This can also be done in c++: an object is constructed with an
invocation operator.  The origingal work is done by the constructor,
and the final work by the invocation operator.
         
From: Gareth McCaughan
Subject: Re: How to touch struct slots
Date: 
Message-ID: <86aemepvrr.fsf@g.local>
"ArolAmbler" wrote:

> One of the STANDARD lisp tricks goes by the name of Currying.
> (I believe after Wm. Curry, but that may be wrong).

Haskell Curry. The language Haskell is named for him too.

-- 
Gareth McCaughan  ················@pobox.com
sig under construction