From my experience, trying to come to grips with pioLisp, I would argue in favour of showing the simple example to explain the concept AND then showing the complex, safe example and explaining why it is more robust and suitable for production use. I agree that there's way too many cases, for other systems, where the examples are trivial and thus lead users to premature complacency.


konrad Zielinski wrote:
I've been thinking about the issue of needing Transient symbols.
On the whole I think it will be better to use transient symbols where necesary.

My line of though is that using destructive operators is exactly where
this is an issue. And that is what I'm trying to write about. I have
to say I'm always annoyed when I've spent a while examining a sample
program in some book, and getting to the Ahh so that's how you do it
moment, only have the author tell me, well that's not how you really
do it because we haven't considered X, Y and Z.

As such I think a more complex but actually safe example is more
valuable, even if in reality you would just use the built in fifo. How
do other people feel about incomplete teaching examples?



On 15/10/2008, konrad Zielinski <[EMAIL PROTECTED]> wrote:
Thanks Alex,

I had misgivings about using eval in my code, and a feeling that there
must be a better way.

The inability to add NIL is something I completely missed, though.
True not somthing that you would ordinarily do at the prompt but quite
likely deep inside application code.

As to useing Transient symbols. I think  I will note it in my
description as you have. As far as I know Inadvertant variable capure
is a problem somwhere in most Lisp dialects. I know it can be an issue
in Common Lisp as well. Granted the circumstancs are different, but
the problem seems to keep cropign up.



On 14/10/2008, Alexander Burger <[EMAIL PROTECTED]> wrote:
Hi Konrad,

I decided to re-implemtn the fifo function using these primitives.
Good idea! This will give a lot of useful and practical examples.

(de my-fifo (Fifo Item)
        (let RealFifo (eval Fifo)
          (if Item
            (if RealFifo # Adding to a Fifo
                  (let NewHead (cons Item (cdr RealFifo))
                        (con RealFifo NewHead)
                        (set Fifo NewHead)
                  (prog # Creating a new fifo
                   (set Fifo (list Item) 'RealFifo (eval Fifo))
                   (con RealFifo RealFifo)
            (if (== RealFifo (cdr RealFifo))
                  (prog1 # Returning the Last Item
                    (car RealFifo)
                    (set Fifo NIL))
              (prog1 # Returning an Item
                    (cadr RealFifo)
                    (con RealFifo (cddr RealFifo)))))))

Questions, Comments, Suggestions ?
There are some minor changes I would suggest:

1. The 'Item' argument is used as an indicator whether a value is going
   to be inserted into the queue (non-NIL), or removed from the queue
   (NIL). The problem is then that NIL itself can never be inserted.

   Therefore, I would suggest to make 'Item' an optional argument, by
   using the '@' notation, and use retrieval functions like (args) and

2. Instead of (eval Fifo) I would use (val Fifo). While this makes no
   difference if 'Fifo' is bound to a symbol, it also allows cell
   arguments (see also the 'var' discussion shortly ago):

      :  (setq L (need 3))
      -> (NIL NIL NIL)

      : (my-fifo (cdr L) 1)
      -> 1
      : (my-fifo (cdr L) 2)
      -> 2
      : (my-fifo (cdr L) 3)
      -> 3

      : L
      -> (NIL (3 1 2 .) NIL)

      : (my-fifo (cdr L))
      -> 1

      : L
      -> (NIL (3 2 .) NIL)

3. The 'prog' ("Creating a new fifo") is not really needed, as it is
   implied in the 'else' part of 'if'. It does no harm, though.

With these changes, my version would be:

   (de my-fifo (Fifo . @)
      (let RealFifo (val Fifo)
         (if (args)
            (if RealFifo  # Adding to a Fifo
               (let NewHead (cons (next) (cdr RealFifo))
                  (con RealFifo NewHead)
                  (set Fifo NewHead)
                  (arg) )
               # Creating a new fifo
               (set Fifo (list (next)) 'RealFifo (val Fifo))
               (con RealFifo RealFifo)
               (arg) )
            (if (== RealFifo (cdr RealFifo))
               (prog1  # Returning the Last Item
                  (car RealFifo)
                  (set Fifo NIL) )
               (prog1  # Returning an Item
                  (cadr RealFifo)
                  (con RealFifo (cddr RealFifo)) ) ) ) ) )

However! Now one ugly detail remains, and I would probably not put this
into such an educational example. But it is one of the sore spots in

4. To make it absolutely correct, all locally bound symbols (i.e. Fifo,
   RealFifo and NewHead) should be transient symbols (i.e. "Fifo",
   "RealFifo" and "NewHead"). Otherwise a call like

      (my-fifo 'Fifo 1)

   would fail. This is explained a bit in "doc/faq.html#problems". Here
   we have the case that a symbol might be bound to itself and its value
   is being accessed.

   For a real production library, I would definitely write it with
   transient symbols. For part of an application, it is usually not so
   critical as you usually have some naming conventions. But even then
   you might run into an error during testing.

- Alex

This message has been scanned for viruses and
dangerous content by MailScanner, and is
believed to be clean.


Reply via email to