Простейший случай: если переменная верхнего уровня происходит от другого модуля
Если переменная верхнего уровня импортируется из другого модуля, как в этой программе:
; other-module.rkt
#lang racket
(provide shadowed)
(define (shadowed x)
'the-normal-result)
; main-module.rkt
#lang racket
(require "other-module.rkt")
(define (f . args)
(define (shadowed x)
; I want to use the shadowed identifier from the other module
(cons 'local-extra (shadowed-from-other-module x)))
(for/list ([arg args])
(shadowed arg)))
Вы можете использовать local-require
следующим образом:
(define (f . args)
(define (shadowed x)
(local-require "other-module.rkt")
(cons 'local-extra (shadowed x)))
(for/list ([arg args])
(shadowed arg)))
Более сложный случай, с использованием операций установки области действия для ссылки на другие области действия
Вы можетесоздайте макросы declare-scope
и in-scope
, которые будут использоваться следующим образом:
#lang racket
(declare-scope top)
(define x "outer")
(let ()
(define x "inner")
(in-scope top x))
;"outer"
Этот API имеет то преимущество, что он все еще работает, если вы оборачиваете все в еще большую область:
(declare-scope top)
(define x "outer")
(let ()
(declare-scope mid)
(define x "middle")
(let ()
(define x "inner")
(in-scope mid x)))
;"middle"
В контексте вашего кода это будет выглядеть следующим образом:
(declare-scope top)
(define (shadowed x)
'the-normal-result)
(define (f . args)
(define (shadowed x)
(cons 'local-extra ((in-scope top shadowed) x)))
(for/list ([arg args])
(shadowed arg)))
Эти макросы могут быть определены с помощью операций с областью действия (в частности, make-syntax-delta-introducer
) вот так:
#lang racket
(require syntax/parse/define)
(define-syntax-parser declare-scope
[(_ name:id)
#:with stx this-syntax
;; This saves the syntax object at compile-time, so that in-scope
;; can reference it later.
#'(define-syntax name (quote-syntax stx))])
(define-syntax-parser in-scope
#:track-literals
[(_ scope exp/def)
;; This gets scope-stx, the syntax object that was saved when the
;; scope was declared.
#:declare scope (static syntax? "scope")
(define scope-stx (syntax-local-introduce (attribute scope.value)))
;; This delta introducer has the scopes that are:
;; - in exp/def
;; - but not in scope-stx
(define delta (make-syntax-delta-introducer #'exp/def scope-stx))
;; This removes the scopes that are in delta.
(delta #'exp/def 'remove)])