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

From: Alexander D. Knauth (alexander at knauth.org)
Date: Sun Dec 28 20:03:09 EST 2014

On Dec 28, 2014, at 5:42 PM, Eli Barzilay <eli at barzilay.org> wrote:

> On Sat, Dec 27, 2014 at 6:21 PM, Alexander D. Knauth
> <alexander at knauth.org> wrote:
>> Is there any way to make the at-exp reader turn @list{A @"string" escape}
>> into (list "A " "string" " escape.),
>> instead of into (list .A string escape.) ?
> The idea behind this is that @|...| can be used to include not only any
> Racket subexpression, but any number of them, so @|x| is just an
> identifier as is often used, and if you need two of them, you can use
> @|x y| which is more convenient than @|x|@|y|

Thanks, this is actually almost perfect, so that way I can do something like
@my-printf{given: ~v and ~v@|x y|}

(But DrRacket colors the second one red, is that a bug?)

> -- and @|| is therefore
> the degenerate case.  This means that you can get what you want with
>    @list{A @|"string"| escape}.
> (Long explanation, but the bottom line would look magical without it...)
> But...
>> The reason is that I wanted to make my own versions of format, printf,
>> fprintf, error, etc. that would work with the at-exp reader and
>> convert something like this:
>> @my-error['f]{message
>>                given: ~v@"something"
>>                other-arguments: ~v@"something-else"
>> ~v@"another-something-else"}
>> into something like this:
>> (error 'f "message\n  given: ~v\n  other-arguments: ~v ~v"
>>       "something" "something-else" "another-something-else")
> ... this is generally a bad idea.  What do you do when you want the
> @"..." escapes?  How do you find out which parts of the input are
> arguments and which are part of the format string?  

For that, I have a helper function that looks at the first argument, sees how many arguments it would take as a format string, and then takes the next n arguments as the place-fillers for that format string, then recursively looks at the next format string.  
;; parse-format-args : (Listof Any) -> (Cons String (Listof Any))
(define (parse-format-args args)
  (match args
    [(list) (list "")]
    [(cons (? string? s (app format-string->num-of-args n)) rst)
     (unless (<= n (length rst))
       (error 'parse-format-args "format string requires ~v arguments, given ~v" n (length rst)))
     (define-values (rst.vs rst.rst) (split-at rst n))
     (match-define (cons rst.rst.s rst.rst.vs) (parse-format-args rst.rst))
     (cons (string-append s rst.rst.s) (append rst.vs rst.rst.vs))]))

> But most of all, IMO it sounds like a bad idea since it tries to fight
> the natural mixed-text-and-expressions and bend it into a
> format-string-like thing.  I'd go with something that avoids that and
> uses @-expressions more naturally, as in:
>    @my-error['f]{message
>                    given: @~v[stuff]
>                    other-arguments: @~v[other-stuff]}

I wanted to be able to format things that can’t be converted to text and back properly, so for example in DrRacket this works:
@my-printf{the plt logo: ~v@(plt-logo #:height 50)}
But this doesn’t:
(display @string-append{the plt logo: @~v[(plt-logo #:height 50)]})
There is a similar-ish thing with syntax-objects and mixed numbers (and there are probably more) in DrRacket.

> and have `my-error' be something like:
>    (define (my-error what . text) (error what "~a" (string-appeng* text)))
> -- 
>          ((lambda (x) (x x)) (lambda (x) (x x)))          Eli Barzilay:
>                    http://barzilay.org/                   Maze is Life!

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.racket-lang.org/users/archive/attachments/20141228/4141eb09/attachment.html>

Posted on the users mailing list.