[英]Using new keywords in Racket macros
作為Racket的練習,我試圖創建一個類似於C的函數,接受return
關鍵字。
當我定義function
宏時:
(require (for-syntax syntax/parse))
(define-syntax (function stx)
(syntax-parse stx
#:datum-literals (return)
[(_ (func-id arg-id ...) body ...)
#'(define (func-id arg-id ...)
(call/cc (lambda (return) body ...)))]))
並使用return
語句創建函數 f
:
(function (f x) (return 100) (+ 1 x))
(f 2)
我得到:
return: undefined;
cannot reference an identifier before its definition
但是,擴展function
宏:
(require macro-debugger/expand)
(syntax->datum (expand-only
#'(function (f x) (return 100) (+ 1 x))
(list #'function)))
返回:
'(define (f x) (call/cc (lambda (return) (return 100) (+ 1 x))))
實際上:
(define (f x) (call/cc (lambda (return) (return 100) (+ 1 x))))
(f 2)
> 100
如預期般運作。
對於我的虛擬情況,可以像這樣在function
定義中替換模式匹配:
[(_ (func-id arg-id ...) (return x-expr) body ...)
#'(define (func-id arg-id ...)
(call/cc (lambda (return) (return x-expr) body ...)))]
但是通常, return
關鍵字可以出現在函數體內的任何位置。
我怎樣才能做到這一點?
我認為您誤會了datum-literals
意思。 datum-literals
用於模式匹配輸入語法,而不用於輸出模板/語法。
您嘗試做的事情完全不能通過重寫規則來完成,因為Racket的衛生宏系統會將您的return
重命名為其他名稱,以避免名稱沖突。
通常的方法是使用語法參數。 恐懼宏已經很好地解釋了這一點,因此在此不再贅述。
這似乎可行:
(require (for-syntax syntax/parse))
(require racket/stxparam)
(define-syntax-parameter return
(lambda (stx)
(raise-syntax-error (syntax-e stx) "can only be used inside aif")))
(define-syntax (function stx)
(syntax-parse stx
[(_ (func-id arg-id ...) body ...)
#'(define (func-id arg-id ...)
(call/cc (lambda (return_k)
(syntax-parameterize ([return (syntax-rules () [(_ val) (return_k val)])])
body ...))))]))
(function (f x) (return 100) (+ 1 x))
(f 2)
我想可以使用make-rename-transformer
改進syntax-parameterize
,但是我沒有成功。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.