Como fazer apenas parte de uma macro higiênica
Pergunta
Eu gostaria de ter uma versão lambda
, chamado lambda-r
, de dentro do qual você pode return
.Um exemplo:
(+ ((lambda-r ()
(return 1)
2)) 5)
Isso daria o valor 6
.Embora você possa esperar que o valor seja 7, ele é 6 porque 1 é retornado da expressão lambda antes de 2 ser alcançado.
Aqui está um exemplo do tipo de transformação que procuro.Digamos que alguém usasse lambda-r
do seguinte modo:
(lambda-r (a b)
(return a)
(+ a b))
Eu quero que seja transformado assim:
(call/cc (lambda (k)
(define return (lambda (v)
(k (lambda (a b)
v))))
(lambda (a b)
(return a)
(+ a b))))
Isso também poderia ser expresso com uma expressão let em vez de uma definição interna, mas estou usando a definição para maior clareza.
Observe que o código acima realmente funciona conforme o esperado. O problema é que estou tendo problemas para expressar lambda-r
como um macro.A razão é que eu quero k
e v
ser higiênico, mas não quero return
para ser higiênico.
Minha macro no momento é esta:
(define-syntax lambda-r
(syntax-rules (return)
[(_ (var ...) body ...)
(call/cc (lambda (k)
(define return (lambda (v)
(k (lambda (var ...)
v))))
(lambda (var ...)
body ...)))
]))
O que não funciona porque return
é tratado de forma higiênica e, como resultado, não é diretamente visível ao usar lambda-r
.Então (lambda-r () (return 1))
dá um erro que diz que return
não é um identificador válido.
Editar:Graças à resposta de Nathan Sanders, estou mais perto de entender o que tenho que fazer aqui.No entanto, não entendo completamente os procedimentos a seguir e, como resultado, ainda não consegui fazer isso funcionar.Eu realmente apreciaria se você pudesse me explicar/direcionar para recursos que explicam o seguinte:
- o
syntax
procedimento - o
datum->syntax
/syntax->datum
procedimentos
Editar:Deixa pra lá - agora entendi :)
Solução
O que você quer é syntax-case
em vez de syntax-rules
.
A definição R6RS dá alguns exemplos, nomeadamente uma seção sobre conversões de objetos de sintaxe e dados, que é o que você deseja.Você deve ser capaz de adaptar o loop
c/ break
exemplo para o seu return
.