A Scheme source file is plain text. The reports define how the text is read and run, not how files are named or stored, so everything on this page about extensions, encodings and the first lines of a file is convention or implementation behaviour, and each point says which.
Extensions and file kinds
| Extension | What it holds | Where it comes from |
|---|---|---|
.scm | Scheme source of any dialect: programs, libraries and scripts | Convention, three letters for old file systems. Also used by GIMP Script-Fu scripts and by Tree-sitter query files, which are not Scheme. |
.ss | Scheme source | Convention of Chez Scheme and of older PLT Scheme code. Also an unrelated name for other text files, which the viewer shows without colour. |
.sld | An R7RS library: one define-library form | Convention of R7RS implementations (Chibi-Scheme and Sagittarius among them); the report does not name an extension. |
.sls | An R6RS library: one library form | Convention of R6RS implementations (Chez, Ikarus, Ypsilon, Larceny, Guile and others); the report does not name an extension. |
.sps | An R6RS top-level program: import, then the code | Convention of R6RS implementations. Also the name of SPSS syntax files, which the viewer shows without colour. |
.sch | A header that a Bigloo program includes | Bigloo’s convention; the name is also used by schematic files of electronics tools, which the viewer shows without colour. |
.rkt | A Racket module, which begins #lang | A different language; see Racket. A .scm or .ss file that begins #lang is a Racket module and the viewer names it so. |
The viewer registers .scm, .ss, .sld, .sls, .sps and .sch. Each of the three library and program kinds is shown under its own name (R7RS Scheme library, R6RS Scheme library, R6RS Scheme program), a file that opens with #lang as a Racket source file, a Tree-sitter query as a Tree-sitter query file, and anything that does not open like Scheme as a text file with a Scheme extension.
Characters, encoding and line endings
R7RS describes a program as a sequence of Unicode characters and says nothing about how they are stored; UTF-8 is what current implementations read. R6RS says the same of its source. Older files, and files from the 1980s and 1990s, may be ASCII or an 8-bit code page; such a file is read by the viewer with the encoding it detects.
A line ending is a newline, a carriage return followed by a newline, or a carriage return alone (R7RS section 7.1.1). R6RS adds the next-line and line-separator characters and a carriage return followed by a next-line. A line ending matters in two places only: it ends a ; comment, and inside a string it is part of the string unless a backslash precedes it (see Lexical structure). Whitespace is space, tab and line endings; implementations may add page break and other characters.
The characters [ ] { } are reserved for future extensions in R7RS. In R6RS the brackets [ ] are lexemes like parentheses ({ } remain reserved), and in practice Chez, Guile, CHICKEN, Gambit and others read square brackets as parentheses, which is why (let ([x 1]) x) is common.
What a file contains
A program
An R7RS program is one or more import declarations followed by expressions and definitions, which run in order when the program is started. The initial environment is empty, so at least one import is needed; a read-eval-print loop starts with the bindings of (scheme base) and others. Many programs in old style (R5RS and earlier) have no import at all, because the implementation provides the whole language.
(import (scheme base) (scheme write))
(define (greet name)
(display "Hello, ")
(display name)
(newline))
(greet "world")
An R7RS library
A library is one define-library form with a name, exports, imports and a body. In R7RS the body is wrapped in begin (or read from files by include), which is how it differs from R6RS.
(define-library (example counter)
(export make-counter)
(import (scheme base))
(begin
(define (make-counter)
(let ((n 0))
(lambda () (set! n (+ n 1)) n)))))
counter.sld.An R6RS library and program
An R6RS library is one library form whose body follows the export and import clauses directly. An R6RS top-level program is an import form and then the code. A file may open with #!r6rs, which the lexical syntax of the report counts as a comment that marks the file as R6RS source.
#!r6rs
(library (example counter)
(export make-counter)
(import (rnrs))
(define (make-counter)
(let ((n 0))
(lambda () (set! n (+ n 1)) n))))
counter.sls.A script
A script is a program started from a shell. Its first line is a shebang line, which for Scheme implementations is read as a comment. Some implementations also accept a block form that ends !#, so that the first lines can pass options to the interpreter through the shell:
#!/usr/bin/env guile
!#
(display "Hello")
(newline)
The viewer reads a #! followed by / or a space at the start of a text as a comment up to the end of the line, or up to a line that is only !# when one follows within 4000 characters.
Directives at the top of a file
#!fold-caseand#!no-fold-case– R7RS directives that turn case folding on and off for the rest of the file; they act like comments (see Lexical structure).#!r6rs– the R6RS marker described above.#!r7rsis used by some R7RS implementations in the same way, but the R7RS report does not define it; the viewer colours both as directives.#lang– the first line of a Racket module; the viewer hands such a file to its Racket colouring.- A character coding line (
;; -*- coding: utf-8 -*-and similar) is an ordinary comment to Scheme; Guile reads such a line for the coding of the file.
Compiled and related files
The reports do not define a compiled form. Implementations write their own: Guile writes .go files, Chez Scheme writes .so files from compile-file, CHICKEN compiles to C and writes .import.scm files that describe the exports of a compiled library. These are binary, differ between versions, and are not registered by the viewer, which shows them as bytes. (Chez and Guile file names are from memory of their manuals; neither manual was read.)
How the viewer reads a file
A .scm text is checked for what it is: Racket if it begins #lang, an R7RS library if its first form is define-library, an R6RS library if its first form is library with a name, an R6RS program if it has #!r6rs and an (import ( form, a Tree-sitter query if it has capture names after closing brackets () @name) or predicates such as (#match? ...) and no Scheme forms, otherwise Scheme. The colouring itself is described on Lexical structure.
Not described
Known, not yet covered
- Reference: the file names and search paths that each implementation uses to find a library from its name (for example Chez’s
--libdirsand Guile’s%load-path) are not described. - Reference: the layout of compiled files is not described.
Unknown
- Reference: the extension names of compiled files and header files of each implementation are from memory and were not checked against the manuals.
See also
- Lexical structure – how the text becomes tokens
- Libraries and modules – the
libraryanddefine-libraryforms in full - Implementations and dialects – what each implementation reads and writes