From: Jonathon McKitrick
Subject: Need help designing a closure properly
Date: 
Message-ID: <1137624078.366982.165030@g14g2000cwa.googlegroups.com>
Perhaps I don't need one after all, but I might as well learn how to
use them, right?

Supposed I have some database functions (not methods) that execute
queries and return the fields of interest.  But after doing that, I'd
like to keep a the key of the located record in case I need more info
later.  I *guess* I could save the key in a global, but I'm trying to
use a closure instead.

Would it make sense in the query function to bind a symbol to the index
value, and return a #'function?  Or should I just define the functions
inside the let scope, and call them as needed?  What's the right way to
do this?

From: RPG
Subject: Re: Need help designing a closure properly
Date: 
Message-ID: <1137635611.311121.185510@g14g2000cwa.googlegroups.com>
An alternative way of doing this is to make a database object, and just
squirrel away a "last record" index as part of the local state of the
database object.  That provides limited caching which I believe is what
you are trying to do....

I don't really understand your objectives perfectly, though.  Do you
just want to keep the last one of these indices?  Multiple ones?  If
you are going to have multiple keys in your cache, how do you get the
right one later on?  I'm not sure what's the expensive computation
you're trying to avoid repeating, etc.
From: jayessay
Subject: Re: Need help designing a closure properly
Date: 
Message-ID: <m3ek35ce3a.fsf@rigel.goldenthreadtech.com>
"Jonathon McKitrick" <···········@bigfoot.com> writes:

> Perhaps I don't need one after all, but I might as well learn how to
> use them, right?
> 
> Supposed I have some database functions (not methods) that execute
> queries and return the fields of interest.  But after doing that, I'd
> like to keep a the key of the located record in case I need more info
> later.  I *guess* I could save the key in a global, but I'm trying to
> use a closure instead.
> 
> Would it make sense in the query function to bind a symbol to the index
> value, and return a #'function?  Or should I just define the functions
> inside the let scope, and call them as needed?  What's the right way to
> do this?

I believe that you are fishing for "memoization" and "memoized
functions".  Also an automatic and convenient way to define these etc.

This has been discussed here at length from time to time and is also
covered by Norvig in _PAIP_ and Graham in _On Lisp_ and probably lots
of other places that I am now forgetting...


/Jon

-- 
'j' - a n t h o n y at romeo/charley/november com
From: Wade Humeniuk
Subject: Re: Need help designing a closure properly
Date: 
Message-ID: <zVzzf.130879$OU5.123200@clgrps13>
Jonathon McKitrick wrote:
> Perhaps I don't need one after all, but I might as well learn how to
> use them, right?
> 
> Supposed I have some database functions (not methods) that execute
> queries and return the fields of interest.  But after doing that, I'd
> like to keep a the key of the located record in case I need more info
> later.  I *guess* I could save the key in a global, but I'm trying to
> use a closure instead.
> 

All that means is that you have to indirectly store the closure by
binding it to a top-level object.  There is no difference.  I am kind
of scratching my head here, but how many of these keys do you need to
keep around.  Just the last one, or a whole bunch?  I would simply suggest
you include the key with the returned fields of interest (after all the key
is just a db field) and keep the query around until you are done.

Wade

> Would it make sense in the query function to bind a symbol to the index
> value, and return a #'function?  Or should I just define the functions
> inside the let scope, and call them as needed?  What's the right way to
> do this?
> 
From: Pascal Bourguignon
Subject: Re: Need help designing a closure properly
Date: 
Message-ID: <87wtgxp1fp.fsf@thalassa.informatimago.com>
"Jonathon McKitrick" <···········@bigfoot.com> writes:
> Perhaps I don't need one after all, but I might as well learn how to
> use them, right?
>
> Supposed I have some database functions (not methods) that execute
> queries and return the fields of interest.  But after doing that, I'd
> like to keep a the key of the located record in case I need more info
> later.  I *guess* I could save the key in a global, but I'm trying to
> use a closure instead.
>
> Would it make sense in the query function to bind a symbol to the index
> value, and return a #'function?  Or should I just define the functions
> inside the let scope, and call them as needed?  What's the right way to
> do this?

There is an equivalence between closures and object.

In the case of a database, usually a query returns a "results" object
with all the needed information for further processing.  This allows
to provide several methods (or functions) to process the results in
different ways.

If you plan to have only "one way" to process results, you could in
effect return a function.

(defun db-request (...)
    ...
    (let ((rows ...))
       (lambda () 
          (prog1 (values (first rows) (null rows)) (pop rows)))))

Then you'd use it as:  

     (let ((results (db-request ...)))
        (loop :for row = (funcall results)
              :while row
              :do (something-with row)))
          

But if you want to provide several entry points, which you can do with
a selector:

(defun db-request (...)
    ...
    (let* ((db ...)
           (keys ...)
           (rows ...)
           (current-rows rows)
       (lambda (selector) 
         (case selector
          (getdb db)
          (next-row (prog1 (values (first current-rows) (null current-rows))
                           (pop current-rows)))
          (reset-rows (setf current-rows rows))
          (refresh  (setf rows (ask-again db keys) current-rows rows))
          ...
          (otherwise (error "Invalid selector ~S" selector)))))))

which you'd use it as:  

     (let ((results (db-request ...)))
        (loop :for row = (funcall results 'next-row)
              :while row
              :do (something-with row))
        (funcall results 'reset-rows)
        (print (list 'first 'row 'was (funcall results 'next-row)))
        (funcall results 'refresh)
        (print (list 'now 'first 'row 'is (funcall results 'next-row)))
        ...)

it becomes ugly and it would be simplier to just return dead data and
provide functions (or methods):

(defun db-request (...)
    ...
    (make-instance 'result ; or make-result, given a (defstruct result ...)
        :db ...  
        :keys ...
        :rows ...
        :current-rows rows)

(defun getdb (result) (result-db result)) ; or a method or accessor

(defun next-row (result) ; or a method
      (prog1 (values (first (result-current-rows result))
                     (null  (result-current-rows result)))
             (pop (result-current-rows result))))

(defun reset-rows (result) ; or a method
    (setf (result-current-rows result) (result-rows result)))

(defun refresh (result) ; or a method
   (setf (result-rows result) (ask-again (result-db result)
                                         (result-keys result))
         (result-current-rows result) (result-rows result)))

...

which you can use simply as:

     (let ((results (db-request ...)))
        (loop :for row = (next-row result)
              :while row
              :do (something-with row))
        (reset-rows result)
        (print (list 'first 'row 'was (next-row result)))
        (refresh result)
        (print (list 'now 'first 'row 'is (next-row result)))
        ...)

-- 
__Pascal Bourguignon__                     http://www.informatimago.com/
You never feed me.
Perhaps I'll sleep on your face.
That will sure show you.
From: Jonathon McKitrick
Subject: Re: Need help designing a closure properly
Date: 
Message-ID: <1137628754.955704.192480@g44g2000cwa.googlegroups.com>
Pascal Bourguignon wrote:
> (defun db-request (...)
>     ...
>     (let ((rows ...))
>        (lambda ()
>           (prog1 (values (first rows) (null rows)) (pop rows)))))

I've never seen this structure before... it's making my brain hurt.
what does the prog1 block do?
From: Panos C. Lekkas
Subject: Re: Need help designing a closure properly
Date: 
Message-ID: <KdBzf.682$Vz5.333@fe04.lga>
"Jonathon McKitrick" <···········@bigfoot.com> wrote in message 
·····························@g44g2000cwa.googlegroups.com...
>
> Pascal Bourguignon wrote:
>> (defun db-request (...)
>>     ...
>>     (let ((rows ...))
>>        (lambda ()
>>           (prog1 (values (first rows) (null rows)) (pop rows)))))
>
> I've never seen this structure before... it's making my brain hurt.
> what does the prog1 block do?
>

Every time you run "db-request", it produces and returns a closure (formed 
by the lambda expression in it).

Now, if you look carefully at the rest of Pascal's code, where he shows how 
you might use it, you will see that this same closure eventually becomes the 
value of the variable "results".

Keep in mind that the "prog1" block returns the first value of the series of 
expressions it will sequentially evaluate. In this case the result is the 
evaluation outcome of  (first rows) because "values" produces the values of 
all the expressions it will evaluate.

Consequently and as a result, your closure once it gets passed onto the 
variable "results" and called through the "funcall", will produce a 
meaningful row value to LOOP for it to work.

I thought it is extremely elegant, when I saw it.

Panos C. Lekkas 
From: Pascal Bourguignon
Subject: Re: Need help designing a closure properly
Date: 
Message-ID: <87slrlosg9.fsf@thalassa.informatimago.com>
"Jonathon McKitrick" <···········@bigfoot.com> writes:

> Pascal Bourguignon wrote:
>> (defun db-request (...)
>>     ...
>>     (let ((rows ...))
>>        (lambda ()
>>           (prog1 (values (first rows) (null rows)) 
>>               (pop rows)))))
>
> I've never seen this structure before... it's making my brain hurt.
> what does the prog1 block do?

1- clhs prog1
   http://www.lispworks.com/reference/HyperSpec/Body/m_prog1c.htm

2- if you suspect it may be a macro, you can macroexpand-1 it.  I'd
   bet most macros are simple enough for their meaning being obvious
   once macroexpanded.  What do you think of this?

   (macroexpand-1 '(prog1 (values (first rows) (null rows)) (pop rows)))
   --> (LET ((#:G4997 (VALUES (FIRST ROWS) (NULL ROWS)))) (POP ROWS) #:G4997) ;
       T

3- There is prog1, prog2 and progN.  They all evaluates all the
   imbricated forms, but return a different result: prog1 returns the
   primary result of the first form, prog2 the primary result of the
   second form, and progN all the results of the last form.

   (prog1 (values 1 :a) (values 2 :b) (values 3 :c) (values 4 :d))
   --> 1
   (prog2 (values 1 :a) (values 2 :b) (values 3 :c) (values 4 :d))
   --> 2
   (progN (values 1 :a) (values 2 :b) (values 3 :c) (values 4 :d))
   --> 4 ;
       :D

   (PROG, PROG* and PROGV are something completely different).

Which means that my program is wrong, doesn't do what I intended (*^.^*)



Usually, you'd just use (pop rows), which already contains a PROG1:
(macroexpand-1 '(pop rows))
--> (PROG1 (CAR ROWS) (SETQ ROWS (CDR ROWS))) ;
    T

But since I wanted to collect (null rows) before the POP and return it
with, I came with this:

  (prog1 (values (first rows) (null rows))
     (pop rows))

(Common Lisp evaluates from left to right).


Now, prog1 doesn't keep the other values, so it's equivalent to:

  (prog1 (first rows)
     (pop rows))


I could have written instead:

   (values-list (nreverse (list (null rows) (pop rows))))

Or plainly:

   (let ((emptyp (null rows)))
     (values (pop rows) emptyp))

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

READ THIS BEFORE OPENING PACKAGE: According to certain suggested
versions of the Grand Unified Theory, the primary particles
constituting this product may decay to nothingness within the next
four hundred million years.
From: Jonathon McKitrick
Subject: Re: Need help designing a closure properly
Date: 
Message-ID: <1137648390.250240.56300@g44g2000cwa.googlegroups.com>
Pascal Bourguignon wrote:
> But since I wanted to collect (null rows) before the POP and return it
> with, I came with this:
>
>   (prog1 (values (first rows) (null rows))
>      (pop rows))

It took a few reads, but I finally figured out prog1 and what it is
used for.  But I still don't get why you call (null rows) when (first
rows) will already return null when the list is empty, right?
From: Pascal Bourguignon
Subject: Re: Need help designing a closure properly
Date: 
Message-ID: <87u0c0oguo.fsf@thalassa.informatimago.com>
"Jonathon McKitrick" <···········@bigfoot.com> writes:

> Pascal Bourguignon wrote:
>> But since I wanted to collect (null rows) before the POP and return it
>> with, I came with this:
>>
>>   (prog1 (values (first rows) (null rows))
>>      (pop rows))
>
> It took a few reads, but I finally figured out prog1 and what it is
> used for.  But I still don't get why you call (null rows) when (first
> rows) will already return null when the list is empty, right?

I didn't assume anything about the elements in rows.

Truth, for a db request, a row most probably will be some list or
vector of values, not NIL.



But in general, if your function may return NIL as a valid value, then
you need a second flag to indicate whether you returned a NIL value or
if there isn't anything more.


(defun enumerator (list)  (lambda () (pop list)))
(defparameter e1 (enumerator '(1 a nil 2 b t)))
(loop :for val = (funcall e1) :while val :do (print val))

Prints only:

1 
A 


(defun enumerator (list)
  (lambda ()
    (multiple-value-prog1 (values (car list) (not (null list)))
      (pop list))))

(defparameter e1 (enumerator '(1 a nil 2 b t)))

(loop :named loop
   :do (multiple-value-bind (val got-data) (funcall e1)
          (unless got-data (loop-finish))
          (print val)))

prints:

1 
A 
NIL 
2 
B 
T


[63]> (defparameter e1 (enumerator '(1 nil)))

E1
[64]> (funcall e1)
1 ;
T
[65]> (funcall e1)
NIL ;
T
[66]> (funcall e1)
NIL ;
NIL


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

"Remember, Information is not knowledge; Knowledge is not Wisdom;
Wisdom is not truth; Truth is not beauty; Beauty is not love;
Love is not music; Music is the best." -- Frank Zappa
From: Coby Beck
Subject: Re: Need help designing a closure properly
Date: 
Message-ID: <xQQzf.110792$km.30829@edtnps89>
"Jonathon McKitrick" <···········@bigfoot.com> wrote in message 
····························@g44g2000cwa.googlegroups.com...
>
> Pascal Bourguignon wrote:
>> But since I wanted to collect (null rows) before the POP and return it
>> with, I came with this:
>>
>>   (prog1 (values (first rows) (null rows))
>>      (pop rows))
>
> It took a few reads, but I finally figured out prog1 and what it is
> used for.  But I still don't get why you call (null rows) when (first
> rows) will already return null when the list is empty, right?

The problem is this:
CL-USER 1 > (defvar foo1 ())
FOO1

CL-USER 2 > (defvar foo2 (list ()))
FOO2

CL-USER 3 > (list (first foo1) (first foo2))
(NIL NIL)

CL-USER 4 > (list (null foo1) (null foo2))
(T NIL)

You must never forget that nil is a perfectly valid list element.

-- 
Coby Beck
(remove #\Space "coby 101 @ bigpond . com")
From: Johan Bockgård
Subject: Re: Need help designing a closure properly
Date: 
Message-ID: <yoijmzhsdhet.fsf@linus003.dd.chalmers.se>
Pascal Bourguignon <····@mouse-potato.com> writes:

> Now, prog1 doesn't keep the other values,

MULTIPLE-VALUE-PROG1

-- 
Johan Bockgård
From: Pascal Bourguignon
Subject: Re: Need help designing a closure properly
Date: 
Message-ID: <8764ogpx4k.fsf@thalassa.informatimago.com>
············@dd.chalmers.se (Johan Bockg�rd) writes:

> Pascal Bourguignon <····@mouse-potato.com> writes:
>
>> Now, prog1 doesn't keep the other values,
>
> MULTIPLE-VALUE-PROG1

Indeed.  Therefore, I'm updating my common-lisp-hyperspec function to
make use of this completion function instead of the obarray
common-lisp-hyperspec-symbols.

(defun common-lisp-hyperspec-complete (string predicate allp)
  (if allp
      (let ((result '()))
        (mapatoms
         (lambda (symbol)
           (let ((name (symbol-name symbol)))
             (when (or (and (<= (length string) (length name))
                            (STRING-EQUAL string name :end2 (length string)))
                       (search (concat "-" string) name))
               (push name result))))
         common-lisp-hyperspec-symbols)
        result)
      (try-completion string common-lisp-hyperspec-symbols predicate)))

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

ATTENTION: Despite any other listing of product contents found
herein, the consumer is advised that, in actuality, this product
consists of 99.9999999999% empty space.
From: Thomas A. Russ
Subject: Re: Need help designing a closure properly
Date: 
Message-ID: <ymifynkgloy.fsf@sevak.isi.edu>
"Jonathon McKitrick" <···········@bigfoot.com> writes:

> 
> 
> Pascal Bourguignon wrote:
> > (defun db-request (...)
> >     ...
> >     (let ((rows ...))
> >        (lambda ()
> >           (prog1 (values (first rows) (null rows)) (pop rows)))))
> 
> I've never seen this structure before... it's making my brain hurt.
> what does the prog1 block do?

PROG1 evalutes its forms in order, but returns the value of the first
form evaluted.


-- 
Thomas A. Russ,  USC/Information Sciences Institute