Every Racket source file begins with a #lang line. (#lang is pronounced hash-lang.)
The #lang line specifies what language should be used to interpret the source code in the file.
There can be only one #lang line per source file. It’s always the first line of code (though it can be preceded by whitespace or comments).
Most often, the simple #lang name notation is used to invoke a language, for instance:
#lang br
#lang br/quicklang
#lang racket/base
#lang pollen/pre
#lang datalog
#lang scribble/manual
Dialects of languages are typically notated with slashes (e.g., br vs. br/quicklang). (Not all languages have dialects—consult the documentation to see which are supported.)
This shorthand #lang name notation only works with languages that have been installed as part of a Racket package. Alternatively, you can use the #lang reader path syntax to specify a local path to a language reader, which can be useful for quick prototypes:
#lang reader "path/to/language-reader.rkt"
Or with #lang s-exp path, you can use Racket’s default S-expression reader with an arbitrary expander:
#lang s-exp "path/to/language-expander.rkt"
More broadly, the #lang line supports metalanguages that can be chained with another language to add new features. For instance, the three language specifications below all rely on racket/base for the heavy lifting, but the second and third get extra features from the at-exp and debug metalanguages, respectively:
#lang racket/base
#lang at-exp racket/base
#lang debug racket/base
Under the hood, the #lang line works by discovering the reader for the language, which is a Racket function. Racket passes all the source code after the #lang line to the reader function, which returns code describing a module. Racket then replaces the source code with this new module code, and evaluation continues from there.
Logical minds might infer that because a #lang line invokes a reader, and the reader returns syntax for a module expression, then every source file that starts with a #lang line will end up with a single module expression at the top level. Yes—this is exactly right.
In fact, every Racket source file consists of a single module expression at the top level. This is why in Racket lingo, a source file is also known as a module.
Thus, even though the #lang line is highly idiomatic, it’s not technically required. In a Racket source file, you can always use a module expression instead of a #lang line. In practice, there’s no reason to do this, but we can use this to demystify what’s happening.
These two programs are the same, and will both print 42:
#lang racket/base
(* 6 7)
(module mod-name racket/base
(* 6 7))
This program is different, however:
#lang racket/base
(module submod-name racket/base
(* 6 7))
It doesn’t print 42 because the #lang line introduces its own module wrapping, so you end up with nested modules like so:
(module mod-name racket/base
(module submod-name racket/base
(* 6 7)))
Though Racket automatically evaluates the top-level module, it doesn’t automatically evaluate nested modules, so submod-name never runs.
Caution: in the above examples, you could easily convert to module form because racket/base source code uses Racket’s standard S-expression reader. But in general, a module expression standing alone can’t invoke a special reader. So even though this would be valid Scribble code:
#lang scribble/text
The product is @(* 6 7).
You can’t do this:
(module mod-name scribble/text
The product is @(* 6 7).) ; triggers a read error
More broadly, this means you can’t mix different readers within a single source file. There can be only one #lang line, and it determines the reader for the whole file.
Anything on the #lang line that follows the name of the main language is treated as part of the source code. So this prints 42:
#lang br (* 6 7)
You can put Racket-style comments before the #lang line, so this also prints 42:
;; line comment
#| block comment |#
#;(commented expression)
#lang br
(* 6 7)
Racket has no officially sanctioned way of passing configuration arguments to a language on the #lang line (maybe someday—it would be useful). Certain languages like scribble/doclang2 support things that look like keyword arguments. But in fact, these arguments are part of the source code, and are being handled specially by the language’s read-syntax function.
#lang scribble/doclang2
#:id doc
#:post-process values
#:exprs ()
"Hello world"
Modules explainer
The #lang Shorthand in the Racket Guide