6. Modules, namespaces and project organization
Sections
Reading settings
No voice for this language in this browser.
More voices
Code and English terms
Off: the page’s voice reads everything, with no pause between two voices.
No voice for this language in this browser.
More voices
More voices: Microsoft Edge has natural online voices, and Windows (Settings › Time & language › Speech), macOS and Android install others.
A namespace gives .NET types a qualified name. A module groups values, functions and types. C# developers often reach for a static class where F# uses a module.
Official references: namespaces, modules, access control and signature files.
Nested modules
Section titled “Nested modules”From l06_modules.fsx:
module Music = module Pitch = let private normalize pitchClass = ((pitchClass % 12) + 12) % 12
let name pitchClass = [| "C"; "C#"; "D"; "Eb"; "E"; "F"; "F#"; "G"; "Ab"; "A"; "Bb"; "B" |] |> Array.item (normalize pitchClass)normalize is visible only inside Pitch; Music.Pitch.name is public. internal exposes a member to the current assembly but not to consumers. Use the narrowest visibility that supports tests through public behavior.
Namespace or module?
Section titled “Namespace or module?”namespace GuitarAlchemist.Theory
module Pitch = let name pitchClass = ...
type Chord(root: int) = member _.Root = rootA namespace cannot directly contain let bindings; put them in a module. A file can begin with module GuitarAlchemist.Theory.Pitch when the entire file is one module.
File order is dependency order
Section titled “File order is dependency order”F# compiles project files top to bottom. A file may use definitions from files listed before it, never after it.
<ItemGroup> <Compile Include="Domain.fs" /> <Compile Include="Parser.fs" /> <Compile Include="Program.fs" /></ItemGroup>This makes dependency direction visible and prevents accidental cycles. Reordering files in the IDE changes the project file and can change whether it compiles.
Signature files
Section titled “Signature files”A .fsi file precedes the matching .fs file and declares the public surface:
module GuitarAlchemist.Theory.Pitch
val name: pitchClass: int -> stringThe implementation may contain helpers that consumers cannot see. Signature files are useful at stable library boundaries, but expensive when every internal function changes; do not add them mechanically to every file.
Exercise
Section titled “Exercise”Split the lesson script into Pitch.fs, Chord.fs and Program.fs, list them in dependency order, then add Pitch.fsi exposing only name. Confirm that trying to call normalize from Program.fs fails at compile time.
Continue with errors and Result.