1. You will need a cooperation of phone-numbers macro. There are two
   ways I am aware of
   1.1 You could hard code in phone-numbers to deal with add-prefix
   directly.
   1.2 A more general approach is to use local-expand in phone-numbers to
   partially expand macros in the body of phone-numbers. In this case, this
   is to partially expand add-prefix to something that phone-numbers can
   recognize and deal with.
   2. The macro add-prefix is weird. It doesn’t expand to the compile-time
   macro number. Instead, it expands to a runtime function application (to
   construct a list of lists) and perform the string-append at runtime.
   This means it would be really hard for phone-numbers to process the
   partially expanded syntax if you were to use approach 1.2. Are you sure
   that this behavior of add-prefix is what you want?

Here’s my attempt to solve this problem, while trying to maintain the
external behavior you described.

#lang racket

(require (for-syntax syntax/parse))

;; number macro is needed so that "bare" add-prefix works correctly

(define-syntax (number stx)
  (syntax-parse stx
    [(_ x:string) #'(list 'number x)]))

(number "123") ; ==> '(number "123")

;; - if the immediate macro is `number`, don't partially expand it, because
;;   `phone-numbers` know how to deal with it already. Note that
;;   the result attribute should be of ellipsis depth 1, so we need to do
;;   some normalization here.
;;
;; - otherwise, partially expand the immediate macro. The protocol is that
;;   the immediate macro should expand to (list (number xxx) ...).
;;   We then extract the result from it.

(begin-for-syntax
  (define-syntax-class do-expand
    #:attributes ([result 1])
    (pattern ({~literal number} _)
             #:with (result ...) (list this-syntax))
    (pattern _
             #:with ({~literal list} result ...)
                    (local-expand this-syntax 'expression #f))))

(define-syntax (phone-numbers stx)
  (syntax-parse stx
    [(_ :do-expand ...)
     (syntax-parse #'((~@ result ...) ...)
       [(((~literal number) phone) ...)
        #'(list phone ...)])]))

(phone-numbers
 (number "1212")
 (number "2121")) ; ==> '("1212" "2121")

;; add-prefix computes at compile-time. It abides the protocol described above.

(define-syntax (add-prefix stx)
  (syntax-parse stx
    [(_ prefix ((~literal number) str) ...)
     #:with (prefixed ...) (map (λ (s)
                                  (datum->syntax
                                   this-syntax
                                   (string-append (syntax-e #'prefix)
                                                  (syntax-e s))))
                                (attribute str))
     #'(list (number prefixed) ...)]))

(add-prefix "555"
            (number "1212")
            (number "2121")) ; ==> '((number "5551212") (number "5552121"))

;; add-suffix computes at compile-time. It abides the protocol described above.

(define-syntax (add-suffix stx)
  (syntax-parse stx
    [(_ prefix ((~literal number) str) ...)
     #:with (suffixed ...) (map (λ (s)
                                  (datum->syntax
                                   this-syntax
                                   (string-append (syntax-e s)
                                                  (syntax-e #'prefix))))
                                (attribute str))
     #'(list (number suffixed) ...)]))

(add-suffix "555"
            (number "1212")
            (number "2121")) ; ==> '((number "1212555") (number "2121555"))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(phone-numbers
 (add-prefix "555"
             (number "1212")
             (number "2121"))
 (number "1234"))

;; similar to typing

(phone-numbers
 (list (number "5551212") (number "5552121"))
 (number "1234"))

;; ==> '("5551212" "5552121" "1234")



On Tue, Aug 20, 2019 at 3:13 PM Brian Adkins <[email protected]> wrote:

> Consider the following two macros:
>
> (require (for-syntax syntax/parse))
>
> (define-syntax (phone-numbers stx)
>   (syntax-parse stx
>     [(_ ((~literal number) phone) ...)
>      #'(list phone ...)]))
>
> (define x (phone-numbers
>            (number "1212")
>            (number "2121"))) ; ==> '("1212" "2121")
>
> (define-syntax (add-prefix stx)
>   (syntax-parse stx
>     [(_ prefix ((~literal number) str) ...)
>      #'(list (list 'number (string-append prefix str)) ...)]))
>
> (define y (add-prefix "555"
>                       (number "1212")
>                       (number "2121"))) ; ==> '((number "5551212") (number
> "5552121"))
>
> I would like to be able to do the following:
>
> (phone-numbers
>  (add-prefix "555"
>              (number "1212")
>              (number "2121"))
>  (number "1234")) ; ==> '("5551212" "5552121" "1234")
>
> I was hoping it would be possible to do this without modifying the
> phone-numbers macro. In other words, to have the result of expanding
> add-prefix macro call be:
>
> (number "5551212") (number "5552121")
>
> So that it would appear to the phone-numbers macro as if the user had
> actually typed:
>
> (phone-numbers
>   (number "5551212")
>   (number "5552121")
>   (number "1234"))
>
> Is it possible to do this w/o the explicit cooperation of the
> phone-numbers macro?
>
> Brian Adkins
>
> --
> You received this message because you are subscribed to the Google Groups
> "Racket Users" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to [email protected].
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/racket-users/e6e5a407-7547-44f1-b8c2-bbe7906ed6f5%40googlegroups.com
> <https://groups.google.com/d/msgid/racket-users/e6e5a407-7547-44f1-b8c2-bbe7906ed6f5%40googlegroups.com?utm_medium=email&utm_source=footer>
> .
>

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/racket-users/CADcuegs_Hce0TKM5rnBuJzV%3D6uRxtbmzZn2V%2BcE3YNHz98OkMw%40mail.gmail.com.

Reply via email to