On Tuesday, August 20, 2019 at 9:11:54 PM UTC-4, Brian Adkins wrote:
>
> On Tuesday, August 20, 2019 at 8:43:07 PM UTC-4, Sorawee Porncharoenwase 
> wrote:
>>
>>
>>    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")
>>
>>
> Thanks. 
>
> The reason the add-prefix macro is weird is because I have no idea what 
> I'm doing with respect to macros, so I'm currently grasping at straws and 
> experimenting :) I appreciate all of the Racket documentation, but I think 
> there is a need for a much better presentation of the material in a 
> graduated way. Racket School was great, but we jumped into the deep end 
> pretty quickly, and the techniques seem "hacky" with odd idiosyncrasies and 
> clever tricks vs. proceeding from a solid foundation and building upon that.
>
> I'm kind of wondering if it wouldn't be easier to just process the syntax 
> object directly - at least then, I'd be in a realm I'm very familiar with.
>
> I'll review the code you've provided.
>

By the way Sorawee, you've been very helpful in your responses to my 
mailing list questions, and you seem to have an excellent grasp of macros. 
How did you acquire your knowledge of macros? 

-- 
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/0a39a0c4-bde5-4207-9abd-63b9d1ceec07%40googlegroups.com.

Reply via email to