Lesson 7.4
References & Further Reading
Module systems, dependency resolution, and topological sort resources.
Module systems: the design space.
Crafting Interpreters — "Resolving and Binding"
Robert Nystrom — craftinginterpreters.com
The resolver chapter covers a semantic pass over the AST that walks scopes and resolves variable references. While Monk's module resolver operates at the file level rather than the variable level, the architecture is the same: a second pass that validates bindings before the final codegen step. Free to read online.
craftinginterpreters.com/resolving-and-binding.htmlGo Packages and Modules
golang.org/ref/spec — the Go language spec
Go's module system (introduced in Go 1.11) is a direct influence on Monk's design. Go separates packages (directory-based namespaces) from modules (versioned dependency units). Monk simplifies this to a single level: one file, one module. Reading Go's package spec shows what Monk chose not to do and why.
go.dev/ref/spec#PackagesMonk's module system is intentionally minimal. No versioning, no package registry, no namespace prefixes. One file = one module. Relative imports only. This covers 95% of real use cases while keeping the resolver under 200 lines.
Graph algorithms: DFS and topological sort.
Topological sorting (Wikipedia)
A linear ordering of a directed acyclic graph's vertices such that for every directed edge u → v, vertex u comes before v. The Wikipedia article covers both Kahn's algorithm (BFS-based, builds order incrementally) and the DFS-based approach that Monk uses. The DFS approach is simpler when you're already doing a recursive traversal.
en.wikipedia.org/wiki/Topological_sortingDepth-first search (Wikipedia)
DFS with gray/black (or white/gray/black) coloring is the standard algorithm for detecting cycles in a directed graph. The three-color version makes cycle detection explicit: a gray node being re-encountered means there is a back edge, which means a cycle. Monk uses this directly in module.Build.
Other module system designs to study.
ECMAScript modules (ESM)
JavaScript's native module system uses static import/export syntax that is resolved at parse time. The spec defines the module record, linking, and evaluation phases as separate steps — a more explicit version of what Monk does with Build / CheckModules / GenerateModules. The design choices map almost directly.
Rust's module system
Rust uses a module tree declared with mod keywords rather than file-based discovery. Visibility is controlled with pub (Monk's export). Rust's approach is more hierarchical; Monk's is flatter and more like Python or JavaScript. Both systems enforce explicit visibility boundaries.
Suggested reading order.
Wikipedia: topological sort — understand DFS post-order as a sorting algorithm before reading the code.
src/module/module.go — read the source. It's under 200 lines and the algorithm maps directly to the theory.
Crafting Interpreters resolver chapter — for understanding scope-based binding resolution at the variable level, which is what the type checker does after the module resolver.
ESM spec — for seeing how a production-grade language formalizes the same three-phase approach (resolve / link / evaluate).