取决于你如何看待它,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行放在文本区域的顶部上面。

1.1 用Racket进行交互

DrRacket的底部文本区和racket的命令行程序(当不带选项启动时)都可以扮作一种计算器。你打出一个racket的表达式,按下回车键,答案就打印出来了。在Racket的术语里,这种计算器叫做一个读取求值打印循环(read-eval-print loop)或REPL

一个数字本身就是一个表达式,而答案就是数字:

> 5

5

一个字符串也是一个求值为自身的表达式。一个字符串在字符串的开始和结尾使用双引号来书写:

> "Hello, world!"

"Hello, world!"

Racket使用圆括号包裹较大的表达式——几乎任何一种表达式,而不是简单的常数。例如,一个函数调用被写为:开括号,函数名,参数表达式和闭括号。下面的表达式用参数"the boy out of the country"47调用内置函数substring

> (substring "the boy out of the country" 4 7)

"boy"

1.2 定义和交互

你能够通过使用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)按钮一样。

1.3 创建可执行程序

如果你的文件(或在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 》部分获取更多信息。

  • 对于UNIX或Mac OS,你可以通过在文件的开头插入以下行将程序文件转换为可执行脚本:

    参见脚本获取有关脚本文件的更多信息。

      #! /usr/bin/env racket

    同时,在命令行中用chmod +x ‹filename› 改变文件权限给可执行文件。

    只要racket在用户的可执行文件搜索路径中脚本就会工作。另外,在#!后面使用一个完整路径提交给racket(在#!和路径之间带一个空格),这样用户的可执行文件搜索路径无关紧要。

1.4 给有LISP/Scheme经验的读者的一个说明

如果你已经知道一些关于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。

更多推荐

Racket编程指南——1 欢迎来到Racket!