From: Vladimir V. Zolotych
Subject: READ-FROM-STRING
Date: 
Message-ID: <3AAB9BA4.B0EE22EE@eurocom.od.ua>
	Hello

- Could you comment '(BASE-STRING 31) ?

  (let ((s (make-array 0 :element-type 'character
  			 :fill-pointer 0 :adjustable t)))
    (with-output-to-string (output-string s)
      (loop repeat 16
  	     do (princ #\a output-string)))
    (values (fill-pointer s) (length s) (type-of s)))
  
  16
  16
  (BASE-STRING 31)
               ^^ why ?
  * 

- Suppose I have "global" variable *alist* 

  (defvar *alist* '())

  I can define function 
  (defun foo (alist)
    ;; do something
    )
  and call it such a way (foo *ALIST*). If I will access ALIST
  inside FOO only in read-only manner -- no questions. I could also
  change parts of *ALIST* (using SETF) through ALIST. But suppose
  I wish to alter *ALIST* through ALIST lexical variable (E.g. (SETF
ALIST ...). 
  This obviously doesn't work. My question is about such attempts.
Should I avoid
  it because it not useful ? Or may be some special technique exists
  for such things ? Please clarify me this point.

- Does it possible to enter strings using READ* in 'PASSWORD' manner ?
E.g.
  echoing entered chars with '*'. Just like Emacs do for command M-x
  send-invisible ?

- The excerpt ion from MaiSQL reference guide

  (loop with time-graph = (make-hash-table :test #'equal)
	with event-graph = (make-hash-table :test #'equal)
	for (time event) being the tuples of "select time,event from log"
       
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
How such extensions (This is the extension, isn't it ?) are integrated
in 
'standard' LOOP syntax. Just give me the idea of how it would be done.

	from *my-db*
	do
	(incf (gethash time time-graph 0))
	(incf (gethash event event-graph 0))
	finally
	(flet ((show-graph (k v) (format t "~40A => ~5D~%" k v)))
	  (format t "~&Time-Graph:~%===========~%")
	  (maphash #'show-graph time-graph)
	  (format t "~&~%Event-Graph:~%============~%")
	  (maphash #'show-graph event-graph))
	(return (values time-graph event-graph)))

- Suppose I have string that must represents integer. Then I
  safely can use PARSE-INTEGER to convert it to some kind of INTEGER.
  Should I use READ-FROM-STRING to obtain FLOAT from corresponding
string ?
  Does more specific (and safe) technique exist ?

	Best regards

-- 
Vladimir Zolotych                         ······@eurocom.od.ua

From: Kent M Pitman
Subject: Re: READ-FROM-STRING
Date: 
Message-ID: <sfwvgpg72b5.fsf@world.std.com>
"Vladimir V. Zolotych" <······@eurocom.od.ua> writes:

> 	Hello
> 
> - Could you comment '(BASE-STRING 31) ?
> 
>   (let ((s (make-array 0 :element-type 'character
>   			 :fill-pointer 0 :adjustable t)))
>     (with-output-to-string (output-string s)
>       (loop repeat 16
>   	     do (princ #\a output-string)))
>     (values (fill-pointer s) (length s) (type-of s)))
>   
>   16
>   16
>   (BASE-STRING 31)
>                ^^ why ?
>   * 

This is just TYPE information for debugging; ignore it.
You asked for an array that you could adjust the size of.
This hints it has allocated you some size to start with so it
won't have to move the array on the first attempt to do what
you've said you're going to do.

> - Suppose I have "global" variable *alist* 
> 
>   (defvar *alist* '())
> 
>   I can define function 
>   (defun foo (alist)
>     ;; do something
>     )
>   and call it such a way (foo *ALIST*). If I will access ALIST
>   inside FOO only in read-only manner -- no questions. I could also
>   change parts of *ALIST* (using SETF) through ALIST. But suppose
>   I wish to alter *ALIST* through ALIST lexical variable (E.g. (SETF
>   ALIST ...). 
>   This obviously doesn't work. My question is about such attempts.
>   Should I avoid
>   it because it not useful ?

Yes.  You will confuse yourself.  You have a pointer to the object, not the
value cell.  This has different implications.

>   Or may be some special technique exists
>   for such things ?

If you *really* (pardon the pun) need the special, you could pass its name,
the symbol itself (by quoting it) and use (setf (symbol-value alist-name) ...)
within the function FOO.

But the simpler thing is to always return the version alist you want to use
from FOO and always call foo by doing (setq *alist* (foo *alist*)).

If you look at the FAQ at http://www.alu.org/ you'll find an explanation
of a similar situation relating to DELETE.  It's a common question
for newcomers to the language to have.

> Please clarify me this point.

Does this clarify?
 
> - Does it possible to enter strings using READ* in 'PASSWORD' manner ?> E.g.
>   echoing entered chars with '*'. Just like Emacs do for command M-x
>   send-invisible ?

This is a UI issue beyond the scope of the portable language.  It is up to
your invidiual vendor's available UI facilities.  I'm sure many are capable
of it, but there is no uniform way.  You didn't say what vendor/implementation
you were using.

> - The excerpt ion from MaiSQL reference guide
> 
>   (loop with time-graph = (make-hash-table :test #'equal)
> 	with event-graph = (make-hash-table :test #'equal)
> 	for (time event) being the tuples of "select time,event from log"
>        
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> How such extensions (This is the extension, isn't it ?) are integrated
> in 
> 'standard' LOOP syntax.

Probably this is done with read-time or compile-time conditionals for
various popular dialects.  Look up *features* in CLHS.

> Just give me the idea of how it would be done.
 
Step 1.  Find out how to do it in your vendor of choice.
Step 2.  Add conditional code for that vendor.
Step 3.  (Optional) Select a new vendor of choice and go to Step 1.

> 	from *my-db*
> 	do
> 	(incf (gethash time time-graph 0))
> 	(incf (gethash event event-graph 0))
> 	finally
> 	(flet ((show-graph (k v) (format t "~40A => ~5D~%" k v)))
> 	  (format t "~&Time-Graph:~%===========~%")
> 	  (maphash #'show-graph time-graph)
> 	  (format t "~&~%Event-Graph:~%============~%")
> 	  (maphash #'show-graph event-graph))
> 	(return (values time-graph event-graph)))
> 
> - Suppose I have string that must represents integer. Then I
>   safely can use PARSE-INTEGER to convert it to some kind of INTEGER.
>   Should I use READ-FROM-STRING to obtain FLOAT from corresponding
>   string ?

It's one way to go.  It's lamentable that there is not a PARSE-FLOAT.
Many vendors may have one privately and you could use such things
conditionally because they might be safer or faster, but fall back to
READ-FROM-STRING in other vendors.

>   Does more specific (and safe) technique exist ?

You should probably bind *READ-EVAL* to FALSE around such a call to avoid
trojan horses and test that the return value was a FLOAT.  You might also
prescan the input before you call READ to make sure it starts with chars
you are happy with or contains only chars you are happy with, in order to
add extra security.

I think there also may be portable float parsers somewhere.  Check at
alu.org.
 
From: Vladimir V. Zolotych
Subject: Re: READ-FROM-STRING
Date: 
Message-ID: <3AABAD02.9217523A@eurocom.od.ua>
Kent M Pitman wrote:
> 
> But the simpler thing is to always return the version alist you want to use
> from FOO and always call foo by doing (setq *alist* (foo *alist*)).
[snip]
> Does this clarify?

Yes, thanks.

> 
> ....  You didn't say what vendor/implementation
Excuse me. I'm using CMUCL 18c 
 

-- 
Vladimir Zolotych                         ······@eurocom.od.ua
From: Pierre R. Mai
Subject: Re: READ-FROM-STRING
Date: 
Message-ID: <87g0gkxhnc.fsf@orion.bln.pmsf.de>
"Vladimir V. Zolotych" <······@eurocom.od.ua> writes:

> - The excerpt ion from MaiSQL reference guide
> 
>   (loop with time-graph = (make-hash-table :test #'equal)
> 	with event-graph = (make-hash-table :test #'equal)
> 	for (time event) being the tuples of "select time,event from log"

[ Ed: This is part of the clause, so reinserted:
> 	from *my-db*
]

> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> How such extensions (This is the extension, isn't it ?) are integrated
> in 
> 'standard' LOOP syntax. Just give me the idea of how it would be done.

Note that the ANSI CL standard does not offer any way for the user to
extend the LOOP macro.  However many implementations (including CMU
CL) use the MIT version of the LOOP macro, which specifies mechanisms
for users to define additional loop iteration paths.

In those implementations that don't use MIT Loop (like e.g. LispWorks
for Windows/Linux, or CLISP, etc.), it is possible to load MIT Loop,
and use that instead of the implementation-defined LOOP facility.

Look at the file sql.cl (function loop-record-iteration-path and the
corresponding call to ansi-loop::add-loop-path) of your MaiSQL
distribution to see how the tuples iteration path is defined.  Further
information on the extension interface of MIT Loop can be gained from
the old Lisp Machine Manuals (and probably Symbolics and other
MIT-derived LM company documentation), by reverse-engineering the
source code, or from the short note I wrote up a couple of years ago,
after reverse-engineering it (attached below).

But beware:  Use this extension capability very judiciously, since
LOOP clauses/keywords are a _global_ resource, i.e. the package system
doesn't protect you from clashes in extensions.  Although you can keep
multiple mutually incompatible extensions in core at a time, through
the use of LOOP universes (see source code for info), this will most
certainly give rise to wild confusion in readers unfamiliar with what
is going on.

Regs, Pierre.

;;;; General Documentation of MIT LOOP extensions
;;;;
;;;; Additional iteration paths (to be used with being clauses) are
;;;; defined via add-loop-path.  It takes the following arguments:
;;;;
;;;; - list of markers/keywords identifying this path
;;;; - function implementing the path (see below)
;;;; - the loop universe to add this path to
;;;; - keyword arguments to specify valid prepositions, user data, etc.
;;;;
;;;; The function that implements the path gets the following parameters:
;;;;
;;;; - variable being iterated on
;;;; - data-type specification of the variable
;;;; - list of preposition phrases
;;;; - the user-data as a rest parameter, if specified
;;;;
;;;; The function has to return a list of either 6 or 10 elements.  If only
;;;; 6 elements are provided, the last 4 elements are appended to get the full
;;;; 10 elements.  The meaning of the elements:
;;;;
;;;; 1) List of bindings to perform at the beginning(?), of the form
;;;;    var, (var), (var initial-value) or (var initial-value data-type).
;;;;    loop-make-iteration-variable is called for each element, passing nil
;;;;    for missing arguments.
;;;; 2) Prologue forms (these are reverse nconced onto *loop-prologue*).
;;;; 3) pre-step-tests
;;;;    Single form.  The collected list of these is passed to make-endtest.
;;;; 4) steps
;;;;    List of forms.
;;;;    The nconced list of these is passed to loop-make-psetq.
;;;; 5) post-step-tests
;;;;    Single form.  The collected list of these is passed to make-endtest.
;;;; 6) pseudo-steps
;;;;    List of forms.
;;;;    The nconced list of these is passed to loop-make-desetq.
;;;;
;;;; The following, if present are identical in meaning to the previous 4
;;;; elements, with the difference that these are used for the first
;;;; iteration only, and the others for the rest.  If they are not present,
;;;; they are treated as identical to the previous 4 elements.
;;;;
;;;; 7) pre-loop-pre-step-tests
;;;;    Single form.  The collected list of these is passed to make-endtest.
;;;; 8) pre-loop-steps
;;;;    List of forms.
;;;;    The nconced list of these is passed to loop-make-psetq.
;;;; 9) pre-loop-post-step-tests
;;;;    Single form.  The collected list of these is passed to make-endtest.
;;;;10) pre-loop-pseudo-steps
;;;;    List of forms.
;;;;    The nconced list of these is passed to loop-make-desetq.
;;;;
;;;; The last 4 or 8 values are passed along to loop-hack-iteration,
;;;; and are indeed identical to the sole elements returned from main
;;;; iteration drivers or for-sub-dispatches.  See
;;;; loop-ansi-for-equals for a simple example of an for-sub-dispatch.
;;;;

-- 
Pierre R. Mai <····@acm.org>                    http://www.pmsf.de/pmai/
 The most likely way for the world to be destroyed, most experts agree,
 is by accident. That's where we come in; we're computer professionals.
 We cause accidents.                           -- Nathaniel Borenstein