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)
>                       Item)
>                 (prog # Creating a new fifo
>                  (set Fifo (list Item) 'RealFifo (eval Fifo))
>                  (con RealFifo RealFifo)
>                 Item))
>           (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
   (next).


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
PicoLisp:

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.

Cheers,
- Alex
-- 
UNSUBSCRIBE: mailto:[EMAIL PROTECTED]

Reply via email to