gpt4 book ai didi

scheme - 将通用 Racket 头加载到当前顶层

转载 作者:行者123 更新时间:2023-12-01 02:00:14 27 4
gpt4 key购买 nike

我想在我编写的几个 Racket 脚本中分享一个简单的代码部分。我不想(需要..)它,但想在顶层运行它(公共(public)代码包括对(current-command-line-arguments)的调用等,所需模块不理解(在至少我不知道这是否可能)。

我尝试(加载)它,但它不起作用,因为它是当前顶级上下文的一部分 - 我在加载上下文中为公共(public) header 中定义的定义收到未绑定(bind)标识符错误。

看来我仍然不理解 Racket 引用第 14 章的某些部分 - 我尝试了 14.1(命名空间)、14.3( Racket /负载)的一些示例,但无法使其正常工作。

我错过了什么?我们如何才能使这样一个看似简单的案例工作?

编辑:这是我的例子:

这是 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: args

更新2

好的,这是我的方法的阶段 1(所谓的宏时间)和阶段 0(所谓的运行时)扩展的更新:

当所有内容都在一个文件中时,我可以在阶段 1(宏)中运行(当前命令行参数):
#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 文件进行双重检查:
调试环境/util.rkt:
#lang racket
(provide f)
(define (f) (display "f from debug"))

发布环境/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

它按我的预期工作。现在,问题是,我不能将整个逻辑放在 common-header.rkt 文件中以供重用。我只是在 Racket Reference 3.2 (Importing and Exporting) 上做更多的阅读,关于 require'ing for-syntax 或直接到阶段级别并提供到阶段级别,我应该了解更多。我在require和provide中使用(for-syntax)取得了更多进展,但还没有:/

更新 3

似乎我太忙于理解阶段级扩展,我又错过了基础知识。来自 header 的简单(提供 if-prototyping)和(require“header.rkt”)实际上正在工作 - 但并不完美:(。Alex在建议 require 应该工作时是正确的。我试图(提供(for-syntax if-prototyping)) 但这不起作用,因为 if-prototyping 在导入模块的 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 我需要标题:
(require "header.rkt")

现在,一个新问题是,header.rkt phase1 定义运行了两次(对于这种情况可能没问题 - 这就是为什么我会接受 Alex 关于使用 require 的回答):
>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

最佳答案

如果您需要使用 current-command-line-arguments 在运行时,使用 require 应该为此工作。这是一个简单的例子:

在 common-code.rkt 中:

#lang racket
(current-command-line-arguments)
(current-command-line-arguments (vector "helloo"))

在文件.rkt 中:
#lang racket
(require "common-code.rkt")
(current-command-line-arguments)

当使用命令行参数 these are my arguments 运行 file.rkt 时,它打印这个:
'#("these" "are" "my" "arguments")
'#("helloo")

当一个文件需要另一个文件时,它总是在另一个文件运行时运行,以及它的运行时影响,包括像 current-command-line-arguments 这样的东西, 在运行时由其他文件的代码看到。此外, current-command-line-arguments 等参数用于当前正在运行的脚本,而不是当前文件。

或者,一个稍微好一点的方法是使公共(public)代码成为一个函数,如下所示:

在 common-code.rkt 中:
#lang racket
(provide setup)
(define (setup)
(println (current-command-line-arguments))
(current-command-line-arguments (vector "helloo")))

在文件.rkt 中:
#lang racket
(require "common-code.rkt")
(setup)
(current-command-line-arguments)

此运行与 these are my arguments也打印出来
'#("these" "are" "my" "arguments")
'#("helloo")

这样,file.rkt 可以更好地控制 if/when/in-what-c​​ontext (setup)被调用,它也可以将参数传递给函数(如果你修改它以接受它们),如果你希望公共(public)代码依赖于 file.rkt 中的某些东西,这将非常有用。

更新

对于您更新的问题,真正的问题似乎是您希望根据命令行参数需要不同的文件。如果没有参数或者第一个参数是 debug ,你想要文件的调试版本,如果第一个参数是其他任何东西,你想要文件的非调试版本。

该文件的两个版本提供了相同的绑定(bind)和相同的目的,换句话说,它们具有相同的接口(interface)。而且因为它们具有相同的界面,所以有几种方法可以做到这一点。

职能

使用最少魔法的方法是让 common-code.rkt 提供一个函数,该函数返回调试或非调试版本的所有函数:

非调试.rkt:
#lang racket
(provide f g)
(define (f x)
(add1 x))
(define (g x)
(* 2 x))

调试.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))

通用代码.rkt:
#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)]))

文件.rkt:
#lang racket
(require "common-code.rkt")
(define-values [f g]
(return-f-and-g))
(f 2)
(g 2)

但是,如果 debug.rkt 和 non-debug.rkt 提供了许多函数,则您必须在 common-code.rkt 中将它们全部枚举两次,并在您使用它的每个文件中枚举一次。
dynamic-require功能

另一种方法是使用 dynamic-require .它将在 common-code.rkt 中像这样使用:
#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))

文件.rkt:
#lang racket
(require "common-code.rkt")
(f 2)
(g 2)

然而,这仍然留下了枚举每个绑定(bind)和编写 (define f (dynamic-require debug-on-non-debug 'f)) 的问题。每一行。

单位

我之前说过,这些方法中的每一个都是可能的,因为 debug.rkt 和 non-debug.rkt 提供了相同的接口(interface)。在 Racket 中表达这一点的一种方式是使用 Units .它们提供了一种将这些东西打包成可以在运行时选择的一流值的方法。 Units有自己的接口(interface)概念,称为 signature .

您可以使用 #lang racket/signature 声明调试和非调试文件的接口(interface)。 .所以在 debug-or-non-debug-sig.rkt 中,输入:
#lang racket/signature
f ; takes a number and adds 1 to it
g ; takes a number and multiplies it by 2

这定义了接口(interface)。最好也写注释来指定 fg做什么,他们接受什么作为参数,他们返回什么,等等。

然后您必须声明调试和非调试文件实现了该接口(interface)。你可以用 #lang racket/unit export 形式。

非调试单元.rkt:
#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))

调试单元.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 。 .

通用代码.rkt:
#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^))

文件.rkt:
#lang racket
(require "common-code.rkt")
(f 2)
(g 2)

如果 file.rkt 在没有命令行参数或 debug 的情况下运行作为第一个参数,它打印:
(f 2)
3
(g 2)
4

但如果它与任何其他参数一起运行,它会打印:
3
4

关于scheme - 将通用 Racket 头加载到当前顶层,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37234158/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com