[racket] at-exp: is there any way to make it turn @list{A @"string" escape} into (list "A " "string" " escape") ?

From: Eli Barzilay (eli at barzilay.org)
Date: Mon Dec 29 19:43:44 EST 2014

On Tue, Dec 30, 2014 at 1:01 AM, Alexander D. Knauth
<alexander at knauth.org> wrote:
>
> On Dec 29, 2014, at 4:53 PM, Eli Barzilay <eli at barzilay.org> wrote:
>
>>    @my-error['x]{blah blah
>>                    blah blah ~v
>>                    @|"something"|}
>
> Yes this would be bad, but part of the whole point of this is that I
> wanted to be able to specify the place-fillers on the same line as the
> place-holders while still having multi-line format strings, so I would
> never do this, and if I put this into a package or something, I would
> be sure to specify that the place-fillers should always be on the same
> line as the place-fillers.

(If it's for private use, then this is mostly irrelevant...)


> But to help this I just added a parameter that would tell it whether
> or not to warn you if one of the place-fillers was the "\n" string.
> (the default is to warn you)

What about an argument that happens to *be* a "\n"?  IIUC, you expect to
turn off the warning for that -- but in many cases you don't know what
the arguments are...  But this was just an example -- it's often useful
to abstract code in ways that break the predictability of where you get
string breaks for various reasons.  I originally had some examples like:

    @foo{blah
         blah}

as a function that expects two strings separated by a "\n" -- but I
quickly concluded that overall, it's a very bad idea, and instead it's
best to view any @-form as something that has "a bunch of text" as its
input, and avoid relying on some specific string splittage.  In cases
where you do want "several bunches of texts", you can use currying:

    (define ((foo . text) . more-text) ...whatever...)

    @@foo{some text}{some more text}

And another alternative which might be more fitting in your case is to
use a macro for the structure:

    @foo[@{some text} @{more text} @{yet more}]

but the convenience in that is minor enough that it's usually better to
just use another function:

    @foo[@bar{some text} @bar{more text} @bar{yet more}]


>> And you can probably also run into surprises when some argument
>> evaluates to a string that has ~s in it.
>
> No, because it never tries to parse an argument as a format string,
> because it knows the number of arguments there should be from the
> previous format string.

I mean that you can get a mess if you make parsing mistakes, or when
format strings change (like the change that added the dotted "~.e" etc
forms).  There's not too much complications in Racket's format strings,
but I wouldn't be surprised if they eventually grow more features.
Another way of looking at it is that there are some extensions, like the
dot thing, that are mostly backward compatible because they only specify
useful stuff for things that used to be invalid -- and the existense of
another piece of code that does format-string-parsing mean that now
*any* change to format strings is a real bug for you.  (So "morally"
speaking, if I'd write such code I'd want a whole pile of tests that
check all valid and invalid format strings, so I know when they change;
or an even better solution would be to expose the Racket format string
parser but that makes it a much heavier tool.)


>> or even ignore voids
>>
>>    (define (my-print . stuff)
>>      (for ([thing (in-list stuff)] #:unless (void? thing))
>>        ((if (string? thing) display print) thing)))
>>
>> so you can do something like:
>>
>>    @my-print{blah @some-value blah @write[another-value] blah}
>
> This is interesting, and solves most of the same "problems," but it
> doesn't extend to things like error.

I don't see why not...  I'm assuming that you have some extension to
exceptions that hold the values to show in some way, so you can just as
well change it to hold thunks that output stuff instead.  Or, if you
want to actually hold the values, the add some struct for "printed
values" that hold the value and how it should be printed.


>> The bottom line is that I'm avoiding the strange mixture of a format
>> string and mixed string/values ("interpolation"), which makes it
>> easier to use.
>
> I understand that, but the processing of the format strings first to
> find out how many arguments they should take should make sure that
> they are never confused with one another, right?  (assuming the
> place-fillers are on the same line as the place-holders)

Yes, assuming no bugs, and ignoring the fact that it's inherently
fragile code.  But it's still a mix of two different styles.

(BTW, yes, there are some points for format strings -- especially when
the expressions become bigger and the text become smaller.  For example
(format "<~a,~a>" (foo-x blah) (foo-y blah)).  But mixing them is the
bad part, IMO.)

-- 
          ((lambda (x) (x x)) (lambda (x) (x x)))          Eli Barzilay:
                    http://barzilay.org/                   Maze is Life!

Posted on the users mailing list.