Macros 具有哈希宏和重命名转换器的Racket
我创造了这个:Macros 具有哈希宏和重命名转换器的Racket,macros,scheme,racket,renaming,transformer,Macros,Scheme,Racket,Renaming,Transformer,我创造了这个: (define-syntax (with-hash stx) (syntax-parse stx [(_ obj:id ((~or key:id [new-key:id hash-key:id]) ...) body:expr ...+) #'(let ([key (hash-ref obj 'key)] ... [new-key (hash-ref obj 'hash-key)] ...) (begin body
(define-syntax (with-hash stx)
(syntax-parse stx
[(_ obj:id ((~or key:id [new-key:id hash-key:id]) ...) body:expr ...+)
#'(let ([key (hash-ref obj 'key)] ...
[new-key (hash-ref obj 'hash-key)] ...)
(begin body ...))]))
这样我就可以做到:
(require rackunit)
(define h (hash 'id 1 'name "scott"))
(with-hash h (id [new-name name])
(check-equal? id 1)
(check-equal? new-name "scott"))
如何添加一种替代模式,在本地自动绑定所有哈希键,而不让客户端在调用中指定它们
即:
我怀疑这涉及到重命名转换器,但是我能够根据运行时哈希声明语法参数并动态重命名它们吗
此外,我认为这样的事情可能是正确的:
(define-syntax (with-hash stx)
(syntax-parse stx
[(_ obj:id (key:id ...) body:expr ...+)
#'(let ([key (hash-ref obj 'key)] ...)
(begin body ...))]
[(_ obj:id body:expr ...+)
#'(with-hash obj (id title) body ...)]))
在这里,我调用宏并解析出要绑定的基准,但在这种情况下,id和title变量没有绑定,即使宏在其他情况下工作
很明显,我的理解中遗漏了一些东西
任何见解都将不胜感激
谢谢。我建议换个方向,坚持提供标识符。在Scheme程序的评估环境中创建/添加标识符时,总是有点可疑。是的,这是允许的,可以安全地完成,但它混淆了人们对什么是约束、何时何地的理解 因此,我建议将您的
和hash
看作一个绑定构造,它允许访问hash
中的字段。这样使用:
(with-hash h ((the-id 'id) (the-name 'name)) ...)
(define-syntax with-hash
(syntax-rules ()
((_ "gen" hash ((fname fkey) ...) body ...)
(let ((obj hash))
(let ((fname (hash-ref obj 'fkey)) ...)
body ...))))
...
))
或者,使用默认名称
(with-hash h (id name) ...)
其实施方式如下:
(with-hash h ((the-id 'id) (the-name 'name)) ...)
(define-syntax with-hash
(syntax-rules ()
((_ "gen" hash ((fname fkey) ...) body ...)
(let ((obj hash))
(let ((fname (hash-ref obj 'fkey)) ...)
body ...))))
...
))
你不能,真的。变量作用域是一个静态属性,而散列的键是一个动态属性,所以任何解决方案都是错误的。但自从你问起,有两个错误的解决方案与你的要求大致相似 您可以使用
eval
。但是当您调用eval
时,您将丢失任何局部变量;看见你也许可以自己编写代码
您可以做的另一件事是通过隐藏#%top
来更改未绑定变量引用的含义,这是隐藏在未绑定(或“可能由顶级环境绑定”)变量的变量引用周围的语法。但这意味着使用hash的将无法对已经具有本地或模块级绑定的任何键进行阴影处理。不管怎样,代码是这样的:
(define-syntax (with-hash stx)
(syntax-case stx ()
[(with-hash h . body)
(with-syntax ([#%top (datum->syntax stx '#%top)])
#'(let-syntax ([#%top
(syntax-rules ()
[(#%top . x)
(hash-ref h 'x)])])
(begin . body)))]))
Dang,Ryan在我试图给出答案时回答道:)无论如何,这里有一个eval的解决方案,与其他人已经表达的警告相同
#lang racket
(require (for-syntax syntax/parse))
(define-syntax (with-hash stx)
(syntax-parse stx
[(_ h:expr body:expr ...+)
#'(begin
(define-namespace-anchor a)
(let ([keys (hash-keys h)])
(define (mk-bind k) `[,k (hash-ref h (quote ,k))])
(eval
`(let ,(map mk-bind keys)
,@(quote (body ...)))
(namespace-anchor->namespace a))))]))
(require rackunit)
(define h (hash 'id 1 'name "scott"))
(with-hash h
(check-equal? id 1)
(check-equal? name "scott"))
编辑:
作为替代,如果你知道你只打算以一种特定的方式使用它,你可以用类似这样的东西来伪装它
#lang racket
(require (for-syntax syntax/parse))
(define-syntax (with-hash stx)
(syntax-parse stx #:datum-literals (check-equal?)
[(_ h:expr (check-equal? key:id val:expr) ...)
#'(let ([keys (hash-keys h)])
(check-true (hash-has-key? h (quote key))) ...
(check-equal? (hash-ref h (quote key)) val) ...)]))
(require rackunit)
(define h (hash 'id 1 'name "scott"))
(with-hash h
(check-equal? id 1)
(check-equal? name "scott"))
谢谢@GoZoner,我编辑了原始帖子以反映允许在绑定中重命名。我同意你的看法,通常我尝试做的是不合适的,但在这一点上,这更像是一个学习练习,而不是任何东西;除非我们真的知道自己在做什么,否则这不是一个好主意。