I would like to have some mechanism, similar to backquote, for
composing text. IOW, something that allows me to write strings, with
some way of escaping to lisp.
I knocked together a prototype, but it seems really horrible and flaky:
(defmacro build-text (stream string)
"A backquote-like syntax for constructing text. Use #\$' to evaluate
what follows as a lisp form. Whitespace is preserved; use #\' to
terminate the form if you want to suppress the terminating space."
(flet ((read-form-and-string (string)
"Reads a form and a string for STRING, preserving whitespace between them."
(let ((length (length string)))
(multiple-value-bind (form position) (read-from-string string t nil :start 1)
(when (and (< position length) (char= (aref string position) #\'))
(incf position))
(when (member (aref string (1- position)) '(#\Space #\Newline) :test #'char=)
(decf position))
(values form (subseq string position))))))
(let* ((chopped
(loop with l = (1- (length string))
with bottom = 0
for top from 0 to (1- (length string))
when (char= #\$ (aref string top))
collect (subseq string bottom top)
when (char= #\$ (aref string top))
do (setq bottom top)
when (= top l) collect (subseq string bottom)))
(first (first chopped))
(rest (rest chopped)))
`(progn
(format ,stream ,first)
,@(mapcar (lambda (s)
(multiple-value-bind (form string) (read-form-and-string s)
`(format ,stream "~a~a" ,form ,string)))
rest)))))
Any suggestions how this idea could be developed ?
[Aside:
Is there a way of doing what is intended here:
(loop ...
when test (progn
collect something ; collect meaningless inside progn
something-else))
without resorting to this:
(loop ...
when test collect something
when test do something-else)
]
In article <···············@pcepsft001.cern.ch>, Jacek Generowicz
wrote:
> [Aside:
>
> Is there a way of doing what is intended here:
>
> (loop ...
> when test (progn
> collect something ; collect meaningless inside progn
> something-else))
>
> without resorting to this:
>
> (loop ...
> when test collect something
> when test do something-else)
>
> ]
Taken literally, it seems you could do something like this:
(loop ...
when test collect (prog1
something
something-else))
But it seems you could also do this:
(loop ...
when test collect (progn
something-else
something))
Zach
Jacek Generowicz <················@cern.ch> wrote in message news:<···············@pcepsft001.cern.ch>...
> I would like to have some mechanism, similar to backquote, for
> composing text. IOW, something that allows me to write strings, with
> some way of escaping to lisp.
Such things already exist in numerous incarnations.
For example, take a look at http://www.cliki.net/Scribble
Jacek Generowicz <················@cern.ch> writes:
> I would like to have some mechanism, similar to backquote, for
> composing text. IOW, something that allows me to write strings, with
> some way of escaping to lisp.
Hmm, I guess that in terms of mileage for effort, the following is the
way to go:
(defmacro build-text (stream &rest forms)
`(progn
,@(mapcar (lambda (f)
(if (stringp f)
`(format ,stream ,f)
`(format ,stream "~a" ,f)))
forms)))
(build-text t "1 + 2 = " (+ 1 2) "
sqrt(3) = " (sqrt 3))
=>
1 + 2 = 3
sqrt(3) = 1.7320508
Jacek Generowicz <················@cern.ch> writes:
> Jacek Generowicz <················@cern.ch> writes:
>
> > I would like to have some mechanism, similar to backquote, for
> > composing text. IOW, something that allows me to write strings, with
> > some way of escaping to lisp.
>
> Hmm, I guess that in terms of mileage for effort, the following is the
> way to go:
>
> (defmacro build-text (stream &rest forms)
> `(progn
> ,@(mapcar (lambda (f)
> (if (stringp f)
> `(format ,stream ,f)
> `(format ,stream "~a" ,f)))
> forms)))
Small nit: you shouldn't use format for writing out a string
in this way... what happens if the string contains ~a (or other
formatting specifications). write-string, perhaps?
Also, mapcar should not be used by this, as you're not really
interested in a list of return values from format :-)
--
Raymond Wiker Mail: ·············@fast.no
Senior Software Engineer Web: http://www.fast.no/
Fast Search & Transfer ASA Phone: +47 23 01 11 60
P.O. Box 1677 Vika Fax: +47 35 54 87 99
NO-0120 Oslo, NORWAY Mob: +47 48 01 11 60
Try FAST Search: http://alltheweb.com/
Raymond Wiker wrote:
> Jacek Generowicz <················@cern.ch> writes:
...
> > Hmm, I guess that in terms of mileage for effort, the following is the
> > way to go:
> >
> > (defmacro build-text (stream &rest forms)
> > `(progn
> > ,@(mapcar (lambda (f)
> > (if (stringp f)
> > `(format ,stream ,f)
> > `(format ,stream "~a" ,f)))
> > forms)))
>
> Small nit: you shouldn't use format for writing out a string
> in this way...
[etc]
(defun build-text (stream &rest things)
(format stream "~{~A~}" things))
seems perfectly adequate to me. Am I missing something?
--
Gareth McCaughan ················@pobox.com
.sig under construc
Raymond Wiker wrote:
> Also, mapcar should not be used by this, as you're not really
> interested in a list of return values from format :-)
Have I overseen something? Isn't the mapcar used to collect the (FORMAT ...)
forms which are then spliced into the progn?
ciao,
Jochen
Jochen Schmidt <···@dataheaven.de> writes:
> Raymond Wiker wrote:
> > Also, mapcar should not be used by this, as you're not really
> > interested in a list of return values from format :-)
>
> Have I overseen something? Isn't the mapcar used to collect the (FORMAT ...)
> forms which are then spliced into the progn?
No. Mea culpa.
--
Raymond Wiker Mail: ·············@fast.no
Senior Software Engineer Web: http://www.fast.no/
Fast Search & Transfer ASA Phone: +47 23 01 11 60
P.O. Box 1677 Vika Fax: +47 35 54 87 99
NO-0120 Oslo, NORWAY Mob: +47 48 01 11 60
Try FAST Search: http://alltheweb.com/
Raymond Wiker <·············@fast.no> writes:
> Jochen Schmidt <···@dataheaven.de> writes:
>
> > Raymond Wiker wrote:
> > > Also, mapcar should not be used by this, as you're not really
> > > interested in a list of return values from format :-)
> >
> > Have I overseen something? Isn't the mapcar used to collect the (FORMAT ...)
> > forms which are then spliced into the progn?
Only if you use (format nil ...)
--
Hilsen
Johan Ur Riise
Johan Ur Riise wrote:
>> Jochen Schmidt <···@dataheaven.de> writes:
>>
>> > Raymond Wiker wrote:
>> > > Also, mapcar should not be used by this, as you're not really
>> > > interested in a list of return values from format :-)
>> >
>> > Have I overseen something? Isn't the mapcar used to collect the (FORMAT ...)
>> > forms which are then spliced into the progn?
> Only if you use (format nil ...)
It's not the results of the format forms that are collected, but the
forms themselves:
[13]> (macroexpand '(build-text t "t" t #\t))
(PROGN (FORMAT T "t") (FORMAT T "~a" T) (FORMAT T "~a" #\t)) ;
T
Jeremy.
In article <···············@pcepsft001.cern.ch>,
Jacek Generowicz <················@cern.ch> wrote:
> I would like to have some mechanism, similar to backquote, for
> composing text. IOW, something that allows me to write strings, with
> some way of escaping to lisp.
>
> I knocked together a prototype, but it seems really horrible and flaky:
>
> (defmacro build-text (stream string)
[...]
Wouldn't it be simpler to implement something like that as a
modification of the readtable?
Just brainstorming...
Pascal
--
"If I could explain it, I wouldn't be able to do it."
A.M.McKenzie
From: Arthur Lemmens
Subject: Re: backquote-like syntax for building strings.
Date:
Message-ID: <3E76259E.945CC267@xs4all.nl>
Jacek Generowicz wrote:
> Is there a way of doing what is intended here:
>
> (loop ...
> when test (progn
> collect something ; collect meaningless inside progn
> something-else))
>
> without resorting to this:
>
> (loop ...
> when test collect something
> when test do something-else)
Yes. You can use:
(loop ...
when test collect something and do something-else)
--
Arthur Lemmens
Arthur Lemmens <········@xs4all.nl> writes:
> Jacek Generowicz wrote:
> > Is there a way of doing what is intended here:
> >
> > (loop ...
> > when test (progn
> > collect something ; collect meaningless inside progn
> > something-else))
> >
> > without resorting to this:
> > (loop ...
> > when test collect something
> > when test do something-else)
>
> Yes. You can use:
> (loop ...
> when test collect something and do something-else)
Another possibility is to use some form of the (non-standard)
WITH-COLLECT or COLLECTING macros. There have been implementations of
that posted to this list, and I believe there's one in Cliki as well
Here's an entry in Cliki that I once wrote:
http://www.cliki.net/COLLECTING
WITH-COLLECT is particularly useful with nested loops, inside closures
or whatever. It does not depend on LOOP.
Regards,
Jorg Hohle
Telekom/T-Systems Technology Center