2017-07-27 25 views
1

說我有這樣一個宏:宏內映射沒有額外的括號?

(define-syntax (choose stx) 
    (define data (syntax->datum stx)) 
    (define args (cadr data)) 
    (define body (cddr data)) 
    (define output 
    `(apply (case (car ,args) 
       ,(map (lambda (choice) 
          `((,(car choice)) ,(cadr choice))) 
         body) 
       (else (displayln "error"))) 
      (cdr ,args))) 
    (println output) 
    #'(void)) 

如果我用這個東西是這樣的(可能有更多的選擇):

(choose args 
     ("run" runsomething) 
     ("del" delsomethingelse)) 

它把它

(apply 
(case (car args) 
    ((("run") runsomething) 
    (("del") delsomethingelse)) 
    (else (displayln "error"))) 
(cdr args)) 

這是無效的代碼,因爲地圖給了它額外的括號。相反,我希望它給我這個:

(apply 
(case (car args) 
    (("run") runsomething) 
    (("del") delsomethingelse) 
    (else (displayln "error"))) 
(cdr args)) 

我怎麼能這樣做?

回答

2

使用unquote-splicing(又名,@)來擺脫圍繞map的列表。

例子:

(define xs '(a b c)) 
`(1 2 ,xs 3 4) ; => '(1 2 (a b c) 3 4) 
`(1 2 ,@xs 3 4) ; => '(1 2 a b c 3 4) 

不過,我注意到,你在輸入的語法變壓器stx 使用syntax->datum。這消除了詞彙信息,其中 可能最終導致問題。它建議使用syntax-casesyntax-parse,它們使用模式匹配來挑選輸入語法和模板的元素 以生成輸出。

(define-syntax (choose stx) 
    (syntax-case stx() 
    [(_choose args 
       (datum fun-expr) 
       ...) 
    #'(apply (case (car args) 
       [(datum) fun-expr] 
       ...) 
       (cdr args))])) 

(define (run-it . xs) (list 'ran-it xs)) 
(define (del-it . xs) (list 'delt-it xs)) 

(choose (list "run" 1 2 3) 
     ("run" run-it) 
     ("del" del-it)) 

Output: '(ran-it (1 2 3)) 
+0

你說'syntax-> datum'去掉了詞法信息,但是沒有通過'datum-> syntax'的第一個參數('ctxt')解決嗎? – Wysaard

+0

不可以。數據 - >語法方法給所有東西都提供相同的上下文(即選擇表單)。參數和fun-exprs可能有不同的上下文。 – soegaard

+0

示例:如果參數由一個宏產生,fun-exprs由另一個宏產生,則上下文不同。 – soegaard