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 <br...@lojic.com> 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 racket-users+unsubscr...@googlegroups.com.
> 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 racket-users+unsubscr...@googlegroups.com.
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