Getting Started
This guide walks you from zero to a working March program. See Installation first if you haven’t built the compiler yet.
Hello, World
Every March file starts with a module declaration. Create hello.march:
mod Hello do
fn main() do
println("Hello, March!")
end
end
Run it:
dune exec march -- hello.march
Output:
Hello, March!
What’s happening:
mod Hello do ... enddeclares a module. Every file must have exactly one top-level module.fn main() do ... endis the program entry point.printlnis a builtin that writes a line to stdout.
A More Complete Program
mod Greet do
fn greet(name : String) : String do
"Hello, " ++ name ++ "!"
end
fn main() do
let message = greet("World")
println(message)
let names = ["Alice", "Bob", "Carol"]
List.iter(names, fn n -> println(greet(n)))
end
end
Run it:
dune exec march -- greet.march
Output:
Hello, World!
Hello, Alice!
Hello, Bob!
Hello, Carol!
Key things to notice:
let x = exprbinds a name (noinneeded; subsequent lines in the block see it)++concatenates stringsList.itertakes a list and a function- Lambdas are written
fn x -> body
Compiling to a Binary
To produce a standalone native binary, use --compile:
dune exec march -- --compile -o greet greet.march
./greet
The compiler runs LLVM, links the C runtime, and produces a native executable.
The REPL
Start an interactive session:
dune exec march -- --repl
Or via forge:
dune exec forge -- interactive
The REPL loads the standard library and drops you into a prompt:
march>
Try some expressions:
march> 1 + 1
2 : Int
march> "Hello" ++ " " ++ "March"
"Hello March" : String
march> let xs = [1, 2, 3, 4, 5]
[1, 2, 3, 4, 5] : List(Int)
march> xs |> List.map(fn x -> x * x)
[1, 4, 9, 16, 25] : List(Int)
The last result is always bound to v:
march> 42 * 2
84 : Int
march> v + 1
85 : Int
See the REPL guide for all commands.
Using forge
forge is the recommended project manager for anything beyond a single file.
Create a new project:
dune exec forge -- new my_app
cd my_app
This scaffolds:
my_app/
├── forge.toml # project manifest
├── src/
│ └── my_app.march # entry point
└── test/
└── my_app_test.march
Build and run:
dune exec forge -- build
dune exec forge -- run
Run tests:
dune exec forge -- test
Program Structure
A typical March program has:
mod MyApp do
-- Type definitions
type Color = Red | Green | Blue
-- Pure helper functions
fn color_name(c : Color) : String do
match c do
Red -> "red"
Green -> "green"
Blue -> "blue"
end
end
-- Entry point
fn main() do
let c = Green
println("Color: " ++ color_name(c))
end
end
The main() function is called automatically when the program starts. Its return type can be Unit (implicit) or Int for an exit code.
Type Annotations
Type annotations are optional but useful for documentation and catching mistakes early:
fn add(x : Int, y : Int) : Int do
x + y
end
Without annotations, the compiler infers everything:
fn add(x, y) do
x + y
end
Both are valid. The compiler will catch type errors either way.
Next Steps
- Language Tour — a comprehensive walkthrough of all syntax
- Type System — algebraic data types, generics, Option/Result
- Pattern Matching — destructuring and exhaustiveness checking
- Actors — concurrent programming with the actor model