scope - 你如何引用一个隐藏的顶级变量?
问题描述
#lang racket
(define (shadowed x)
'the-normal-result)
(define (f . args)
(define (shadowed x)
(cons 'local-extra (top-level-shadowed x)))
(for/list ([arg args])
(shadowed arg))) ;I want to be careful that I don't accidentally call the top-level shadowed func here
如上所示,有时我想在本地隐藏顶级函数,因为我想调用一个变体,而变体应该调用顶级函数。
经验表明,给本地变体起一个变体名称,例如shadow^
,会导致错误,因为我不小心从内部范围调用了顶级函数。
我如何才能“跳出”内部范围,或者以某种方式限定标识符以引用其在顶层或明确指定的模块中的绑定?
更新
我发现了一些看起来很有希望的东西:#%top。但是,当我尝试它时,这就是我得到的:
> (define (f x) (list 'top x))
> (define (g x)
(define (f x) (cons 'inner ((#%top . 'f) x)))
(cons 'here (f x)))
. #%top: not an identifier in: (quote f)
> (define (g x)
(define (f x) (cons 'inner ((#%top . f) x)))
(cons 'here (f x)))
?: free identifier found in linklet
解决方案
最简单的情况:如果顶层变量来自另一个模块
如果顶层变量是从另一个模块导入的,就像在这个程序中一样:
; 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)])
推荐阅读
- javascript - 可以在 HTML 正文的末尾注册 Web 组件(JavaScript 原生)吗?
- python - 多尺度模板匹配,规范方法不起作用
- mysql - Mac 更新并重新启动后,我的 sql 服务器无法工作 - 错误 2002 (HY000): Can't connect to local MySQL server through socket '/tmp/mysql.sock'
- language-agnostic - 基于堆栈的语言:寄存器的优缺点?
- javascript - 为什么我的 Discord 机器人会从其他渠道删除消息而不向变量添加值?
- python - Python程序实现一个矩阵来表示树的父-(子)子关系
- reactjs - 尝试将 React Spring 与 Semantic UI React 一起使用,简单示例
- django - Django如何将旧格式的url转换为新的格式路径
- javascript - React - Elements UI - 通过包装 div 大小隐藏的下拉菜单
- c++ - 如何在 C++ 中将十六进制 shellcode 字符串转换为无符号字符数组?