取决于你如何看待它,Racket语言是:
一种编程语言(programming language)——Lisp语言的一种方言和Scheme的一种派生语言;
参见《Racket和Scheme的方言》以获取更多关于Lisp其它方言的信息以及它们与Racket的关系。
编程语言的一个家族(family)——Racket的变体,以及更多的;
一系列工具(tools)——用于编程语言的一个家族。
在不会有混乱的情况下,我们简单地使用Racket。
Racket的主要工具是:
racket, 核心编译器、解释器和运行时系统;
DrRacket, 编程环境;
raco, 用于执行为安装软件包、建立库等等的Racket命令的一个命令行(command-line)工具。
最有可能的是,你想使用DrRacket探索Racket语言,尤其是在开始阶段。如果你要更进一步,你还可以使用命令行racket解释器和你喜欢的文本编辑器;也可以参见《命令行工具和你的编辑器选择》。本指南的其余部分介绍这个语言大多都无关于你的编辑器选择。
如果你正在使用DrRacket,就将需要选择适当的语言,因为DrRacket可以容纳许多不同Racket变体,以及其它语言。如果你以前从未使用DrRacket,启动它,在DrRacket顶上的文本区域键入这一行:
#lang racket
然后点击文本区域上方的Run(运行)按钮。DrRacket接着就明白你的意思是在Racket的正常变体下工作(相对于较小的racket/base或许多其它的可能性来讲)。
《更多的Racket》描述一些其它的可能性。
如果你之前用除了以#lang开始的一个程序之外程序使用过DrRacket,那么DrRacket会记住你使用的这个最后的语言,而不是从#lang推断这个语言。在这种情况下,使用Language|Choose Language...(语言|选择语言……)菜单项。在出现的对话框中,选择第一项,它告诉DrRacket使用通过#lang在源程序中申明的这个语言。仍然要把#lang行放在文本区域的顶部上面。
DrRacket的底部文本区和racket的命令行程序(当不带选项启动时)都可以扮作一种计算器。你打出一个racket的表达式,按下回车键,答案就打印出来了。在Racket的术语里,这种计算器叫做一个读取求值打印循环(read-eval-print loop)或REPL。
一个数字本身就是一个表达式,而答案就是数字:
> 5 5
一个字符串也是一个求值为自身的表达式。一个字符串在字符串的开始和结尾使用双引号来书写:
> "Hello, world!" "Hello, world!"
Racket使用圆括号包裹较大的表达式——几乎任何一种表达式,而不是简单的常数。例如,一个函数调用被写为:开括号,函数名,参数表达式和闭括号。下面的表达式用参数"the boy out of the country"、4和7调用内置函数substring:
> (substring "the boy out of the country" 4 7) "boy"
你能够通过使用define表定义像substring那样工作的你自己的函数,像这样:
(define (extract str) (substring str 4 7))
> (extract "the boy out of the country") "boy"
> (extract "the country out of the boy") "cou"
虽然你可以在REPL中求值define表,但定义通常是你想去保持并今后使用的一个程序的一部分。所以,在DrRacket中,你通常会把定义放在顶部文本区——被称作定义区域(definitions area)——随着#lang前缀一起:
#lang racket (define (extract str) (substring str 4 7))
如果调用(extract "the boy")是程序的主要行为的一部分,那么它也可以进入定义区域。但如果这只是一个例子,你用来测试extract,那么如上面那样你会更原意离开定义区域,点击运行(Run),然后会在REPL中对(extract "the boy")求值。
当使用命令行的racket代替DrRacket,你可以用你喜欢的编辑器在一个文件中保存上面的文本。如果你将它保存为"extract.rkt",然后在同一目录启动racket,你可以对以下序列求值:
如果你使用xrepl,你可以使用,enter extract.rkt。
> (enter! "extract.rkt") > (extract "the gal out of the city") "gal"
enter!表加载代码并将求值上下文转换到模块里面,就像DrRacket的运行(Run)按钮一样。
如果你的文件(或在DrRacket的定义区域里)包含:
#lang racket (define (extract str) (substring str 4 7)) (extract "the cat out of the bag")
那么它是一个在运行时打印“cat”的完整程序。你可以在DrRacket中运行程序或在racket中使用enter!运行程序,但如果程序被保存在‹src-filename›中,你也能够从命令行运行它
racket ‹src-filename›
将程序打包为可执行文件,你有几个选择:
在DrRacket,你可以选择Racket|Create Executable...菜单项。
从一个命令行提示符,运行raco exe ‹src-filename›,这里nonterm{src-filename}包含这个程序。参见《raco exe: Creating Stand-Alone Executables 》部分获取更多信息。
参见脚本获取有关脚本文件的更多信息。
#! /usr/bin/env racket |
同时,在命令行中用chmod +x ‹filename› 改变文件权限给可执行文件。
只要racket在用户的可执行文件搜索路径中脚本就会工作。另外,在#!后面使用一个完整路径提交给racket(在#!和路径之间带一个空格),这样用户的可执行文件搜索路径无关紧要。
如果你已经知道一些关于Scheme或Lisp的东西,你可能会试图这样将
(define (extract str) (substring str 4 7))
放入"extract.rkt"并且按如下运行racket
> (load "extract.rktl") > (extract "the dog out") "dog"
这将会工作,因为racket会模仿传统的Lisp环境,但我们强烈建议不要使用load或在模块之外编写程序。
在模块之外编写定义会导致错误消息、糟糕的性能以及难以组合和运行的脚本程序。这些问题并非特定于racket,它们是传统顶层环境的基本限制,Scheme和Lisp实现在历史上与特别的命令行标志、编译器指令和构建工具进行斗争。模块系统是为了避免这些问题而设计的,所以用#lang开始,从长远来看,你会更喜欢Racket。