1.13 Programs and Modules🔗ℹ

When you write a program using #lang plait, you are technically defining a module. A Plait module contains a mixture of expressions and definitions. The expressions are evaluated in order, and the value of each expression is printed after the expression is evaluated (unless the result value has type Void). The order of function definitions doesn’t matter, as long as a function definition appears before any expression that eventually calls the function.

#lang plait
 
(define (is-odd? x)
  (if (zero? x)
      #f
      (is-even? (- x 1))))
 
(is-odd? 0) ; ok
#;(is-odd? 1) ; won't work, because it needs is-even?
 
(define (is-even? x)
  (if (zero? x)
      #t
      (is-odd? (- x 1))))
 
(is-even? 1) ; ok
(is-odd? 1) ; ok

Note the use of #; in the example above. A #; comments out the entire form that follows it, which is handy for commenting out a definition of expression, even when the definition or expression spans multiple lines.

Modules written with the module form can be nested in other modules. A nested module is called a submodule. Plait programs don’t often use submodules that are written with module, but the module+ form is more common. A module+ form creates a submodule by merging all module+s that use the same name. A typical use of module+ is to move all of a program’s tests into a test submodule.

#lang plait
 
(define (is-odd? x)
  (if (zero? x)
      #f
      (is-even? (- x 1))))
 
(module+ test
  (is-odd? 0)
  (is-odd? 1))
 
(define (is-even? x)
  (if (zero? x)
      #t
      (is-odd? (- x 1))))
 
(module+ test
  (is-even? 1)
  (is-odd? 1))

The submodule name test is special, because DrRacket automatically runs a test submodule (if one is present) after running the enclosing module. In the above example, since the test submodule is run after the encloding module that defines is-odd? and is-even?, the tests can use all of the functions. Another advantage of putting tests in a test submodule is that you can turn off the tests. In DrRacket’s Language menu, select Choose Language, click Show Details, click Submodules to run, and then uncheck the test item.

A Plait module’s definitions are automatically exported from the module. You can import the definitions of another module by using the require form, typically with a string that is a relative path to the module to import.

"math.rkt"

#lang plait
(define pi 3.14)
(define tau (+ pi pi))

"circle.rkt"

#lang plait
(require "math.rkt")
 
(define (circle-area [r : Number]) : Number
  (* pi (* r r)))

A submodule created by module+ automatically imports the bindings of the enclosing module, which is why (module+ test ....) submodules can automatically access definitions for testing. In contrast, if you write definitions inside (module+ test ....), then the definitions can be used for tests in any (module+ test ....), but the enclosing module will not see the definitions.