这里有一个简单的代码部分,我想在我编写的几个脚本中共享。我不想(要求.)它,但希望在顶层运行它(通用代码包括对(当前命令行参数)的调用,等等,所需模块不理解这些调用(至少我不知道这是否可能)。
我尝试(加载)它,但是它不能工作,因为它是当前顶级上下文的一部分--我在加载上下文中获得了一个未绑定标识符错误,用于在公共标题中定义的定义。
似乎我仍然不理解第14章的一些部分的球拍参考-我尝试了一些14.1 (命名空间),14.3 (球拍/负载)的例子,但无法使它发挥作用。
我遗漏了什么?我们如何才能使这样一个看似简单的案例奏效呢?
编辑:下面是我的案例中的一个例子:
这是header.rkt:
#lang racket/load
(define-for-syntax args (current-command-line-arguments))
(define-for-syntax PROTOTYPING (or
(= (vector-length args) 0)
(equal? (vector-ref args 0) "local")))
(define-syntax (if-prototyping stx)
(syntax-case stx ()
((_ debug-expr non-debug-expr)
(if PROTOTYPING
#'debug-expr
#'non-debug-expr))))
(if-prototyping
(require (prefix-in "ci:" (file "/debugenvpath/utils.rkt")))
(require (prefix-in "ci:" (file "/releaseenvpath/utils.rkt"))))
; arrange arguments
(define args (current-command-line-arguments))
(if-prototyping
(set! args (if (= (vector-length args) 0)
(vector "arg1")
(vector (vector-ref args 1))))
#t)这是一个使用它的文件(让我们调用这个test.bat):
; @echo off
; "C:\Program Files\Racket\racket.exe" "%~f0" %*
; exit /b
#lang racket
(require "header.rkt")
"hello, args are: "
args运行test.bat将为文件的最后一行提供以下错误:
args: unbound identifier in module in: argsUpdate2
好,下面是我的方法的phase1 (所谓的宏时间)和phase0 (所谓的运行时)扩展的更新:
当所有内容都在一个文件中时,我可以在phase1 (宏)中运行(当前命令行参数):
#lang racket
(define-for-syntax args (current-command-line-arguments))
(define-for-syntax PROTOTYPING (or
(begin
(printf "phase1 expansion, args are: ~a\n" args)
(= (vector-length args) 0))
(equal? (vector-ref args 0) "local")))
(begin-for-syntax
(printf "phase1, val for PROTOTYPING is: ~a\n" PROTOTYPING))
(define-syntax (if-prototyping stx)
(syntax-case stx ()
((_ debug-expr non-debug-expr)
(if PROTOTYPING
#'debug-expr
#'non-debug-expr))))
(if-prototyping
(require (prefix-in "ci:" (file "./debug-env/util.rkt")))
(require (prefix-in "ci:" (file "./release-env/util.rkt"))))
; arrange arguments
(define args (current-command-line-arguments))
(printf "phase0 expansion, args are: ~a\n" args)
(if-prototyping
(set! args (if (= (vector-length args) 0)
(vector "my-testing-arg-to-use-from-drracket")
(vector (vector-ref args 1))))
#t)
"util func call: "
(ci:f)有用于双重检查的util.rkt文件: debug-env/util.rkt:
#lang racket
(provide f)
(define (f) (display "f from debug"))释放-env/util.rkt:
#lang racket
(provide f)
(define (f) (display "f from release"))这是测试运行的输出:
>test-commonheader.bat local arg1 arg2
phase1 expansion, args are: #(local arg1 arg2)
phase1, val for PROTOTYPING is: #t
phase0 expansion, args are: #(local arg1 arg2)
"util func call: "
f from debug
>test-commonheader.bat arg1 arg2
phase1 expansion, args are: #(arg1 arg2)
phase1, val for PROTOTYPING is: #f
phase0 expansion, args are: #(arg1 arg2)
#t
"util func call: "
f from release如我所料。现在,问题是,我不能将整个逻辑放在一个通用的Header.rkt文件中来重用。我只是做了一些更多的阅读在球拍参考3.2 (导入和导出),还有更多,我应该理解的要求‘为-语法或直接到一个阶段的水平,并提供’阶段-级别。在需求和提供(for-语法)方面,我取得了一些进展,但还没有实现:/
更新3
似乎我忙于理解阶段级扩展,我又一次错过了基础知识。一个简单的(提供if-原型)从头和(要求"header.rkt")实际上是工作-但不是完美的:(。阿历克斯在某种程度上正确地建议了要求应该有效。我试图(提供(用于语法的)if-原型),但这不起作用,因为if-原型是在导入模块的phase0中使用的。
以下是最新的标题:
#lang racket
(provide if-prototyping)
(define-for-syntax args (current-command-line-arguments))
(define-for-syntax PROTOTYPING (or
(begin
(printf "phase1 expansion, args are: ~a\n" args)
(= (vector-length args) 0))
(equal? (vector-ref args 0) "local")))
(begin-for-syntax
(printf "phase1, val for PROTOTYPING is: ~a\n" PROTOTYPING))
(define-syntax (if-prototyping stx)
(syntax-case stx ()
((_ debug-expr non-debug-expr)
(if PROTOTYPING
#'debug-expr
#'non-debug-expr))))
(if-prototyping
(begin
(require "debug-env/util.rkt")
(provide (all-from-out "debug-env/util.rkt")))
(begin
(require "release-env/util.rkt")
(provide (all-from-out "release-env/util.rkt"))))在test-commonheader.bat er.bat中,我需要标题:
(require "header.rkt")现在,一个新的问题是,header.rkt phase1定义运行了两次(这在这种情况下可能是可以的-这就是为什么我将接受Alex关于使用要求的答案):
>test-commonheader.bat arg1 arg2
phase1 expansion, args are: #(arg1 arg2)
phase1, val for PROTOTYPING is: #f
phase1 expansion, args are: #(arg1 arg2)
phase1, val for PROTOTYPING is: #f
phase0 expansion, args are: #(arg1 arg2)
#t
"util func call: "
f from release发布于 2016-05-17 06:39:35
增编-答复和讨论的后续行动
由于亚历克斯为马太的介绍性链接,我在39:31找到了答案之一。(要求(用于语法拍/基)解释缺少的部分。
我会在这里简单解释一下。首先,我必须将“编译时”和“运行时”的术语改为phase1 & phase0。您可以运行任何代码在“任何”-time与球拍。您只需将必要的绑定放到您所处的范围中即可。
当代码在phaseN上运行时,它可以运行编译后的代码或进行语法转换,这是不相关的--这意味着使用“编译时”和“运行时”这两个词必然会混淆人们,仅仅是因为他们对使用劣等编程语言的现象的陈规定型暴露。
当您不进行任何宏编程时,所有内容都在phase0 (所谓的运行时)中。阶段在某种程度上增加了绑定的维护方式(可能是绑定标识符的前缀,在所有绑定都存在的表中)。
当运行一段代码时,它会检查是否可以从它的作用域访问所有必需的绑定。这意味着我们在phase0 (运行时)、phase1 (编译时)或phaseN (根据自身运行时,按阶段(N1)编译时)并不重要。重要的是绑定是否可以从该阶段到达。在我们上面的示例问题中,(当前命令行参数)只是一个绑定,需要通过一些评估将其带到当前阶段。
我们就是这样做的:
让我们看看它的作用:
如果我们试图在.for-语法中使用(当前命令行-参数)。表单,只有#lang球拍/底座,因为它在phase1中没有绑定,它会指出它有一个错误:
#lang racket/base
(define-for-syntax args (current-command-line-arguments))
(define-for-syntax PROTOTYPING (or (= (vector-length args) 0)
(equal? (vector-ref args 0) "local")))
(begin-for-syntax
(printf "phase1, val for PROTOTYPING is: ~a\n" PROTOTYPING))上述产出如下:
current-command-line-arguments: unbound identifier in the transformer environment;
also, no #%app syntax transformer is bound in: current-command-line-arguments但如果我们加上(第2行)必要的要求:
#lang racket/base
(require (for-syntax racket/base))
(define-for-syntax args (current-command-line-arguments))
(define-for-syntax PROTOTYPING (or (= (vector-length args) 0)
(equal? (vector-ref args 0) "local")))
(begin-for-syntax
(printf "phase1, val for PROTOTYPING is: ~a\n" PROTOTYPING))然后输出(取决于您从哪里运行它,这里显示了运行到REPL的一个drracket ):
phase1, val for PROTOTYPING is: #t
phase1, val for PROTOTYPING is: #t
phase1, val for PROTOTYPING is: #t为什么它取决于,为什么会有多条线?我不是百分之百肯定,但有一种感觉,它与“独立汇编担保”,球拍参考1.1.10.2。因为,正如您所看到的,输出是“外部”效应(输出到I/O设备--这里是屏幕),单独的编译不能保证其稳定(或绑定?)。
但是(似乎?)如果您想要使用动态行为进行语法转换,那么您可以使用以下方法:
#lang racket/base
(require (for-syntax racket/base))或者只需在下面使用上面的内容和更多的内容(当然,也增加会话的内存利用率):
#lang racket发布于 2016-05-15 03:29:12
如果您需要在运行时使用current-command-line-arguments,那么使用require就可以了。下面是一个简单的例子:
共同之处-code.rkt.:
#lang racket
(current-command-line-arguments)
(current-command-line-arguments (vector "helloo"))在file.rkt中:
#lang racket
(require "common-code.rkt")
(current-command-line-arguments)当使用命令行参数file.rkt运行these are my arguments时,它会打印以下内容:
'#("these" "are" "my" "arguments")
'#("helloo")当一个文件需要另一个文件时,它总是在另一个文件运行时运行,它的运行时效果,包括current-command-line-arguments之类的东西,由另一个文件的代码在运行时看到。另外,像current-command-line-arguments这样的参数是针对正在运行的当前脚本,而不是当前文件。
或者,一种稍微好一些的方法是使公共代码成为一个函数,如下所示:
共同之处-code.rkt.:
#lang racket
(provide setup)
(define (setup)
(println (current-command-line-arguments))
(current-command-line-arguments (vector "helloo")))在file.rkt中:
#lang racket
(require "common-code.rkt")
(setup)
(current-command-line-arguments)使用these are my arguments运行时,也会打印出
'#("these" "are" "my" "arguments")
'#("helloo")这样,file.rkt可以更好地控制是否/何时/ in -in- (setup)被调用,并且它还可以将参数传递给函数(如果您修改它以接受它们),如果您希望公共代码依赖于file.rkt中的某些内容,这将非常有用。
更新
使用更新的问题,真正的问题似乎是您希望根据命令行参数需要一个不同的文件。如果没有参数,或者第一个参数是debug,则需要文件的调试版本,如果第一个参数是其他参数,则需要文件的非调试版本。
文件的两个版本以相同的目的提供相同的绑定,换句话说,它们具有相同的接口。因为它们具有相同的接口,所以有几种方法可以做到这一点。
函数
使用最少魔法的方法是让公共code.rkt提供一个函数,该函数可以从调试版本或非调试版本返回所有函数:
非首次亮相:
#lang racket
(provide f g)
(define (f x)
(add1 x))
(define (g x)
(* 2 x))debug.rkt:
#lang racket
(provide f g)
(require (prefix-in - "non-debug.rkt"))
(define (f x)
(printf "(f ~v)\n" x)
(-f x))
(define (g x)
(printf "(g ~v)\n" x)
(-g x))公共代码.:
#lang racket
(provide return-f-and-g)
(define (return-f-and-g)
(define args (current-command-line-arguments))
(define debug? (or (= (vector-length args) 0)
(equal? (vector-ref args 0) "debug")))
(cond [debug?
(local-require "debug.rkt")
(values f g)]
[else
(local-require "non-debug.rkt")
(values f g)]))file.rkt:
#lang racket
(require "common-code.rkt")
(define-values [f g]
(return-f-and-g))
(f 2)
(g 2)但是,如果debug.rkt和非调试器use提供了许多函数,则必须枚举所有这些函数的公共代码.use两次,并在您使用它的每个文件中枚举一次。
dynamic-require函数
另一种方法是使用dynamic-require。它将像这样共同使用- like .like:
#lang racket
(provide f g)
(define args (current-command-line-arguments))
(define debug? (or (= (vector-length args) 0)
(equal? (vector-ref args 0) "debug")))
(define debug-on-non-debug (if debug? "debug.rkt" "non-debug.rkt"))
(define f (dynamic-require debug-on-non-debug 'f))
(define g (dynamic-require debug-on-non-debug 'g))file.rkt:
#lang racket
(require "common-code.rkt")
(f 2)
(g 2)然而,这仍然留下了枚举每个绑定和为每个绑定编写一个(define f (dynamic-require debug-on-non-debug 'f))行的问题。
单位
我之前说过,这些方法中的每一种都是可能的,因为debug.rkt和非调试器the提供了相同的接口。在球拍中表达这一点的一种方法是使用单位。它们提供了一种将这些东西打包成可以在运行时选择的一流值的方法。单位有自己的接口概念,称为签名。
可以使用#lang racket/signature声明调试和非调试文件的接口。因此,在调试-或非调试-sig.rkt中,放置:
#lang racket/signature
f ; takes a number and adds 1 to it
g ; takes a number and multiplies it by 2它定义了接口。也可以编写注释,说明f和g所做的事情、作为参数的内容、返回的内容等等。
然后,您必须声明调试和非调试文件实现了该接口。您可以使用#lang racket/unit和export表单来实现这一点。
非调试单元.non:
#lang racket/unit
(require "debug-or-non-debug-sig.rkt")
(import)
(export debug-or-non-debug^)
(define (f x)
(add1 x))
(define (g x)
(* 2 x))调试-unit.rkt:
#lang racket
(require "debug-or-non-debug-sig.rkt")
(import)
(export debug-or-non-debug^)
(define (f x)
(printf "(f ~v)\n" x)
(add1 x))
(define (g x)
(printf "(g ~v)\n" x)
(* 2 x))然后,您可以在运行时选择要使用的这些文件中的哪个,并使用表单define-values/invoke-unit。
公共代码.:
#lang racket
(provide (all-defined-out))
(require "debug-or-non-debug-sig.rkt"
"debug-unit.rkt"
"non-debug-unit.rkt")
(define args (current-command-line-arguments))
(define debug? (or (= (vector-length args) 0)
(equal? (vector-ref args 0) "debug")))
(define-values/invoke-unit (if debug? debug@ non-debug@)
(import)
(export debug-or-non-debug^))file.rkt:
#lang racket
(require "common-code.rkt")
(f 2)
(g 2)如果file.rkt运行时没有命令行参数,或者使用debug作为第一个参数,则会打印如下:
(f 2)
3
(g 2)
4但是,如果它与任何其他参数一起运行,则会打印如下:
3
4https://stackoverflow.com/questions/37234158
复制相似问题