Re: SETF for functions returning multiple values.
"David McClain (as dbm at refined-audiometrics dot com)" <[email protected]> Tue, 9 Jun 2026 03:57:09 -0700
| Newsgroups | gmane.lisp.lispworks.general |
|---|---|
| Message-ID | <[email protected]> |
The real trick here, and to keep things totally portable, you have to build your number readers using READ-CHAR. Do not use READ, until you have something you know will be read correctly. So if I have a pattern that selects out just the conventional number portion of an extended number syntax, then I can use READ-FROM-STRING on that substring. And I surround the read with WITH-VANILLA-READTABLE to prevent inadvertent recursion. Before Pascal showed the way with non-terminating macros, I had been trying to patch over the internal read routines using advice. That took a lot of reverse engineering, and was just waiting to break. And that worked just fine for me until SBCL totally rewrote their reader last year. Then it all broke. I had to discover that you are only in charge so long as you use READ-CHAR. - DM > On Jun 9, 2026, at 03:43, David McClain (as dbm at refined-audiometrics dot com) <[email protected]> wrote: > > The only hitch that I ran into, when making all digits and + and -, into non-terminating macro characters in the readtable - is that when printing out items, the PRINT-OBJECT apparently uses the *READTABLE* to discern when it should insert an escape backslash ahead of every character. > > So I grab a plain vanilla copy of a readtable and keep it around for thwarting this ugly result. With an around method (PRINT-OBJECT :AROUND (SYMBOL T)) I do: > > ———————————————— > > (defvar *vanilla-readtable* (copy-readtable nil)) > > (defmacro with-vanilla-readtable (&body body) > `(let ((*readtable* *vanilla-readtable*)) > ,@body)) > > (let (#+:LISPWORKS (lw:*handle-warn-on-redefinition* nil)) > ;; Prevent printouts from using xxx\-\1\2\3 for xxx-123, etc. ; <- make the digit magic invisible ;-) > (defmethod print-object :around ((object symbol) out-stream) > (with-vanilla-readtable > (call-next-method)))) > > ————————————————————— > > Then, just for safety purposes, I ensure that any attempt to modify the *READTABLE* is prevented if it is the vanilla readtable… > > ——————————————————— > > (defun report-attempt-to-write-vanilla-readtable (rt) > (when (eq rt *vanilla-readtable*) > (error "Vanilla Readtable is Read-Only!"))) > > #+:LISPWORKS > (progn > (lw:defadvice (set-dispatch-macro-character not-in-vanilla-readtable :before) > (disp-char sub-char function &optional (readtable *readtable*)) > (declare (ignore disp-char sub-char function)) > (report-attempt-to-write-vanilla-readtable readtable)) > > (lw:defadvice (set-macro-character not-in-vanilla-readtable :before) > (char function &optional non-terminating-p (readtable *readtable*)) > (declare (ignore char function non-terminating-p)) > (report-attempt-to-write-vanilla-readtable readtable))) > > ————————————————— > > There is a similar pair of advice for SBCL. > > With these patches in place I have not run into any problems from my extended number syntax. > > - DM > > >> On Jun 9, 2026, at 03:17, Madhu (as enometh at meer dot net) <[email protected]> wrote: >> >> * "David McClain (as dbm at refined-audiometrics dot com)" <[email protected]> : >> Wrote on Mon, 8 Jun 2026 11:13:44 -0700: >>> I made my own digits become macro characters so that I can directly >>> handle numbers written like these: >>> +1°23’.23 >>> 2026/06/08T11:10:09U+7 >>> 520-234-3474 >>> and of course any number can be written with embedded comma or >>> underscore: 1_234.5192_5542_112D0 >> >> Thanks, (I remember this as something I couldn't solve decades ago >> when I tried to use the reader) >> >> (comment to tfb below) >> >>> I love it! Lisp no longer feels like a straightjacket to me. I can >>> just directly type in the numbers as I need them. >>> >>> The only other time in my life where I had such freedom was in my >>> ancient Forth Mount Control Systems on the world’s largest telescopes. >>> >>>> On Jun 8, 2026, at 11:02, Tim Bradshaw (as tfb at tfeb dot org) >>>> <[email protected]> wrote: >> >>>> (setf (values p1 p2) <form-returning-two-values>) should work when >>>> p1 and p2 are places (the spec talks about this). >> >>>> If F is a function returning two values, then you can't write a >>>> (SETF F) function for it, but you can write a setf expansion pretty >>>> easily. So then you just can say (setf (f ...) (values v1 v2)). >>>> >>>> I don't think I've seen this done elsewhere. Does it strike people >>>> as reasonable? >>>> >>>> The reason I'm asking is that the delimited-string reading thing >>>> I've been cleaning up now lets you control the closing delimiter, so >>>> that for instance #D[foo/bar.ldat] might read as the contents of the >>>> file foo/bar.ldat (ie the opening and closing delimiters are >>>> different now, which they used not to be. >>>> >>>> The function which lets you set up handlers is get-dsr-handler and >>>> it now returns two values the handler (or NIL) and the closing >>>> delimiter (or NIL if it's the same as the opening delimiter). >>>> >>>> So I want to be able to say (setf (get-dsr-handler #\[) (values >>>> my-handler #\])) say. >> >> I'd just use a cons. My cmucl-init has a read-verbatim-string reader >> with this comment >> >> ``` >> (defvar *matching-delim-pairs* '((#\( . #\)) (#\{ . #\}) (#\[ . #\])) >> "Alist of (LDELIM . RDELIM) characters, for delimiting strings read by >> VERBATIM-STRING-READER.")) >> >> (setf (documentation 'verbatim-string-reader 'function) #$<reads >> $#X...X, where "..." is read verbatim. X, the first character read is >> treated as the delimiter. If *USE-MATCHING-DELIM-PAIRS-P* is non-NIL >> (default), look in the alist *MATCHING-DELIM-PAIRS* to find a matching >> delimiter, which is then used to terminate reading the string<)) >> ``` >> >> (I think I had to set the documentation string in a separate form >> because of I couldn't evaluate the (defun ...) form in emacs -- in >> certain lisps -- if i put it inside the function) >> >> >>>> [The actual hidden motivation for this is an utterly perverse usage >>>> I thought of: you can make any digit character be an opening >>>> delimiter and the closing delimiter for all of them be #\., and with >>>> a suitable handler function >>>> >>>> ? #D1213,456,789. >>>> 1213456789 >>>> >>>> And even >>>> >>>>> #16DFFFF FF00 ABCD. >>>> 281474959977421 >>>> >>>> So that's pretty neat.] >> >> _______________________________________________ >> Lisp Hug - the mailing list for LispWorks users >> [email protected] >> http://www.lispworks.com/support/lisp-hug.html >