在开发程序时,很多Racket程序员使用DrRacket编程环境。要在没有开发环境的情况下运行程序,请使用racket(用于基于控制台的程序)或gracket(对于GUI程序)。本章主要介绍如何运行racket和gracket。
gracket可执行文件和racket一样,但表现上有小的调整,可作为GUI应用程序而不是控制台应用程序。例如,gracket在默认情况下以交互模式运行,使用GUI窗口而不是控制台提示符。然而,GUI应用程序可以以普通的racket运行。
根据命令行参数的不同,racket或gracket在交互模式、模块模式或加载模式下。
当racket在没有命令行参数的情况下运行时(除了配置选项,如-j),那么启动REPL使用> 提示符:
Welcome to Racket v8.4 [cs]. |
> |
为了增强你的REPL体验,请参见《xrepl》;有关GNU Readline支持的信息,请参见《readline》。
要初始化REPL的环境,racket首先需要racket/init模块,该模块提供所有racket,并安装pretty-print以显示结果。最后,在启动REPL之前,racket加载(find-system-path 'init-file)报告的文件(如果存在)。
如果提供了任何命令行参数(配置项除外),请添加-i或--repl以重启REPL。例如,
racket -e '(display "hi\n")' -i
在启动时显示“hi”,但仍显示REPL。
如果需要标志的模块出现在-i/--repl之前,它们将取消对racket/init的自动需求。这种行为可用来使用其它语言初始化REPL的环境。例如,
racket -l racket/base -i
使用更小的初始语言(加载速度更快)启动REPL。请注意,大多数模块都不提供Racket的基本语法,包括函数调用语法和require。例如,
racket -l racket/date -i
生成一个对每个表达式都失败的REPL,因为racket/date只提供了几个函数,而不是REPL里需要求值顶层函数调用所需的#%top-interaction和#%app绑定。
如果一个需求标志的模块出现在-i/--repl之后,而不是出现在它之前,那么该模块需要在racket/init之后,以增强初始环境。例如,
racket -i -l racket/date
除了racket的导出之外,可以使用racket/date启动一个有用的REPL。
如果一个文件参数在任何命令行开关(除了其它配置选项)之前提供给racket,那么这个文件作为一个模块导入,没有REPL启动。例如,
racket hello.rkt
需求"hello.rkt"模块,然后退出。文件名、标志或其它内容之后的任何参数都作为命令行参数保存,以供所需的模块通过current-command-line-arguments使用。
如果使用命令行标志,则可以使用-u或--require-script标志来显示地将文件作为模块。-t或--require标志类似,只是额外的命令行标志由racket处理,而不是为需求的模块保留。例如,
racket -t hello.rkt -t goodbye.rkt
需求"hello.rkt"模块,然后需求"goodbye.rkt"模块,再然后退出。
-l或--lib标志类似于-t/--require,但它需求一个使用lib模块路径而不是文件路径的模块。例如,
racket -l raco
与运行不带参数的raco可执行文件是一样的,因为raco模块是可执行文件的主模块。
请注意,如果你想将命令行标志传递给上面的raco,你需要用--保护这些标志,这样racket就不会试图自己解析它们:
racket -l raco -- --help
-f或--load标志直接支持文件中的load顶级表达式,而不是模块文件中的表达式。这个求值就像启动一个REPL并直接键入表达式,只是结果不打印。例如,
racket -f hi.rkts
load "hi.rkts"并退出。请注意,由于给有LISP/Scheme经验的读者的一个说明中解释的原因,加载模式通常是一个坏主意;使用模块模式通常更好。
-e或--eval标志接受表达式直接求值。与文件加载不同,表达式的结果是打印的,就像在REPL中一样。例如,
racket -e '(current-seconds)'
打印自1970年1月1日以来的秒数。
对于文件加载和表达式求值,顶级环境的创建方式与交互模式相同:除非首先指定了另一个模块,否则需求racket/init。例如,
racket -l racket/base -e '(current-seconds)'
很可能运行得更快,因为它使用较小的racket/base语言而不是racket/init初始化求值环境。
Racket文件可以在UNIX和Mac OS上转换为可执行脚本。在Windows中,像Cygwin这样的兼容层支持相同类型的脚本,或者可以将脚本实现为批处理文件。
在UNIX环境(包括Linux和Mac OS)中,可以使用shell的#!约定将Racket文件转换为可执行脚本。文件的前两个字符必须是#!;下一个字符必须是空格或/,并且第一行的其余部分必须是执行脚本的命令。对于某些平台,第一行的总长度限制为32个字符,而且有时需要空间。
使用#lang racket/base代替#lang racket来生成启动时间更快的脚本。
最简单的脚本格式使用racket可执行文件的绝对路径,随后是模块声明。例如,如果racket安装在"/usr/local/bin"中,那么包含以下文本的文件将充当“Hello World”脚本:
#! /usr/local/bin/racket |
#lang racket/base |
"Hello, world!" |
特别是,如果将上述内容放入文件"hello"中,并使该文件可执行(例如,使用chmod a+x hello),然后在shell提示符处键入./hello将生成输出"Hello, world!"。
上述脚本之所以有效,是因为操作系统自动将脚本的路径作为#!启动的程序的参数行,并且因为racket将单个非标志参数视为包含要运行的模块的文件。
一种流行的代替方法是,不指定racket可执行文件的完整路径,而是需求racket位于用户的命令路径中,然后“trampoline“使用/usr/bin/env:
#! /usr/bin/env racket |
#lang racket/base |
"Hello, world!" |
在任何一种情况下,脚本的命令行参数都可以通过current-command-line-arguments获得:
#! /usr/bin/env racket |
#lang racket/base |
(printf "Given arguments: ~s\n" |
(current-command-line-arguments)) |
如果需要脚本的名称,可以通过(find-system-path 'run-file)获取,而不是(current-command-line-arguments)。
通常,处理命令行参数的最佳方法是使用racket提供的command-line表解析它们。默认情况下,command-line表从(current-command-line-arguments)中提取命令行参数:
#! /usr/bin/env racket |
#lang racket |
|
(define verbose? (make-parameter #f)) |
|
(define greeting |
(command-line |
#:once-each |
[("-v") "Verbose mode" (verbose? #t)] |
#:args |
(str) str)) |
|
(printf "~a~a\n" |
greeting |
(if (verbose?) " to you, too!" "")) |
尝试使用--help标志运行上述脚本,以查看脚本允许哪些命令行参数。
更普通的trampoline使用/bin/sh加上一些行,这些行是一种语言的注释,另一种语言是表达式。这个trampoline更复杂,但它提供了对racket命令行参数的更多控制:
#! /bin/sh |
#| |
exec racket -e '(printf "Running...\n")' -u "$0" ${1+"$@"} |
|# |
#lang racket/base |
(printf "The above line of output had been produced via\n") |
(printf "a use of the `-e' flag.\n") |
(printf "Given arguments: ~s\n" |
(current-command-line-arguments)) |
请注意,#!在Racket中开始一行注释,#|...|#形成块注释。同时,#还启动了一个shell脚本注释,而exec racket则中止了shell脚本以启动racket。这样,脚本文件就变成了/bin/sh和racket的有效输入。
类似的技巧也可以用于在windows中编写Racket代码.bat批处理文件:
; @echo off |
; Racket.exe "%~f0" %* |
; exit /b |
#lang racket/base |
"Hello, world!" |
有关创建和分发可执行文件的信息,参见在《(part ("(lib scribblings/raco/raco.scrbl)" "top"))》中的(part ("(lib scribblings/raco/raco.scrbl)" "exe"))》和《(part ("(lib scribblings/raco/raco.scrbl)" "exe-dist"))》。
(part ("(lib scribblings/raco/raco.scrbl)" "top")).