每个Racket模块都存在自己的文件。
#lang racket
(provide print-cake)
;draws a cake with n candles
(define (print-cake n)
(show " ~a " n #\.)
(show " .-~a-. " n #\|)
(show " | ~a | " n #\space)
(show "---~a---" n #\-))
(define (show fmt n ch)
(printf fmt (make-string n ch))
(newline))
其它模块可以引入cake.rkt来使用print-cake函数,因为provid行明确导出了print-cake函数。而show函数时私有,因为它没有导出。
#lang racket
(require "cake.rkt")
(print-cake (random 30))
"cake.rkt"通过require导入相同目录的文件。unix风格的相对目录在所以平台上用来作为相对模块引用。
6.1.1组织模块
上面代码的列子展示了最通用模块代码组织方式:把所有的文件放在一个目录或者子目录里,然后通过相对路径来引用。模块的目录能被当成一个项目,因为它能整个在系统文件里移动或者拷贝到其它机器上,相对路径保存了彼此之间的模块连接。
racket工具都会自动使用相对路径来工作。比如
racket sort.rkt
在命令行运行上述命令会自动加载编译相关模块。如果程序足够大,从源代码编译太耗时间,可以使用
raco make sort.rkt
命令来编译"sort.rkt"和它依赖的文件到字节码文件。再运行
racket sort.rkt将会自动使用字节码文件当它们存在的时候。
6.1.2库集合
一个集合是一个层次组织的一按的库模块。集合易用通过一个没有引号和后最的路径。
当你搜索在线文档,搜索结果就表明了提供绑定的模块。当你在文档里点击一个超链接,停留在绑定名称上也可以显示提供它的模块。
一个模块的引用像racket/date
看上去像一个标识符,但是它其实不会被当做标识符处理,它会转化成基于集合的引用
- 首先,如果路径没有/,
require
会自动添加/main
。比如require slideshow
等价于require slideshow/main
- 其次,
require
隐式添加".rkt"后缀 - 最后,
require
通过安装的集合搜索路径,而不是把路径当成相对于封闭的模块路径
一个集合实现像一个文件系统目录。但是这只是require查找的其中一个地方。包括用户定义目录,还有PLTCOLLECTS配置的路径,还有安装的包都是查找的范围。
6.1.3包和集合
包是安装在racket包管理器的库集合(包括已经预先安装在racket分发包里的)。比如racket/gui由gui提供,paser-tools/lex由parser-tools提供。
racket程序不直接引用包。程序通过集合引用库,添加或者移除包会改变集合库。集合可以安装不同的包,但是包管理器会保证不发生冲突。相见包管理的文档。
6.1.4添加集合
回顾上面的例子,假设db和mechine模块都需要帮助函数。帮助函数能放在util目录下,而db和mechine都能通过相对路径../utils/来引用。一个程序员可以按照相关路径来引用而不用知道你的racket配置。
一些库是给多个项目使用的,所以把这个库的源代码放在和使用它的模块一起并没有什么意义。在这种情况下,最好添加一个新的集合。当这个库被安装到集合以后,她就能用没有引号的方式引用,就像racket分发包里的库一样。
你能添加一个新的集合,只要在racket的安装目录放置文件,也可以在函数get-collects-search-dirs
返回的目录。此外,你也可以设置PTLCOLLECTS
变量来添加搜索目录。当然,直接添加一个包的方式是最佳选择。
创建一个包并不意味着你必须注册这个包或者执行打包步骤复制源代码到一个归档文件。创建一个包只是简单的意味着包管理器使你的包可以在本地像集合一样被访问。
举例来说,假设你有一个目录/usr/molly/bakery包含cake.rkt模块以及相关模块。为了让这个模块可以像bakery集合一样,你可以
- 使用明令行中的raco命令
rako pkg install --link /usr/molly/bakery
--link参数不是必须的,当目录里有分隔符的时候,你可以省略。 - 使用DrRacket包管理选项(在文件目录下)。执行该选项,选择目录/usr/molly/bakery,然后安装。
在这之后,只要使用(require bakery/cake)
就能引用这个模块下的函数。
默认情况下,你安装的目录名字被当做包名和集合名来使用。淡然,包管理器安装的库也只对当前用户有效,如果想对所有人有效,可以看racket包管理章节。
如果你打算分发你的包,请小心选择你的包名。集合的命名空间是分层的,但是顶级的集合名是全局的,而且包的命名空间是平的。可以使用像molly
一样的标识符来区分作者,然后把库放在洗面。
当你的包被安装到集合以后,你还是可以使用raco命令编译库源码,使用raco setup更好。它使用集合名病情编译集合里的所有库。此外,它还会构建集合文档到文档索引,当你在集合里指定了info.rkt。