#lang在模塊文件的開始處是一種module形式的簡寫。就像'是quote的簡寫。但是#lang不能在repl里使用,一部分原因是它必須使用文件end-of-file接受,也因為簡寫表達是#lang依賴閉合的文件。
6.2.1module 形式
module定義,在repl和文件里都有效
(module name-id initial-module-path
decl ...)
name-id是模塊名,initial-module-path是默認導入,而且每一個decl都市一個導入,導出,定義,或者表達式。當在文件里的時候,name-id一般和包含它的文件同名,但是不包括路徑或者文件后綴。當通過文件路徑引用模塊時,name-id會被忽略。
initial-module-path是必要的,因為即使是require形式也必須導入才能使用。換句話說,initial-modult-path導入了方法體里的可用語法。最常用的模塊是racket,它提供了包括require,define,provide和文檔里的大多數(shù)綁定。另外一個常用模塊時racket/base,也提供了大多數(shù)需要的函數(shù)和語法。
在repl里面可以用模塊語法直接定義一個模塊,而且只要使用模塊名就可以引用該模塊。
定義一個模塊不會馬上致謝模塊的第一個和表達式。當模塊被引用的時候將觸發(fā)執(zhí)行。但是它只會在第一次引用時(require),才會執(zhí)行。
6.2.2#lang簡寫
lang簡寫沒有特別的語法,因為語法被#lang的語句定義。比如這樣:
#lang racket
decl ...
它和下面等價
(module name racket
decl...)
上面形式的方法名可以通過文件名來推斷。
6.2.3子模塊
模塊能內嵌在模塊里面,內嵌的模塊定義了一個子模塊。子模塊在模塊里面可以用名字直接引用。
運行一個模塊不會直接運行子模塊,它們會獨立運行。
子模塊也可以內嵌子模塊。其它模塊可以通過子模塊路徑來引用自模塊。
(module* name-id inital-module-path-or-#f
decl ...)
它和module不同的地方在于
module無法訪問包含它的模塊的綁定和環(huán)境。
-
module可以訪問包含它的模塊的綁定,通過require,但是包含環(huán)境無法導入子模塊。
此外,module形式可以定義#f代替initial-modult-path,那么子模塊可以使用封閉環(huán)境的任何東西,包括沒通過provide導出的。
一個應用module* #f的應用是在模塊里默認不導出子模塊,除非你指定導出子模塊。代碼類似于(require (submod "rake.rkt" extras))
6.2.4主要和測試子模塊
運行一個模塊并不會運行內部的module*定義的子模塊。但是命名為main的子模塊會運行。如果main模塊不需要使用閉包模塊,它可以使用module定義。或者使用module+
(module+ name-id
decl ...)
一個使用module+的模塊就像使用module*,并且用#f來作為initial-module-path參數(shù)。而且,module+的name-id可以一樣,所有同名的module+方法體聯(lián)合起來構建一個子模塊。這種合并行為特別適合用來構建測試。只要在命令行里欲行 raco test ...就可以運行其中的測試。否則加載模塊不會欲行測試代碼。
使用module+可以使代碼分布在不同的地方。而且使用module+更具有可讀性。