March Docs

Prelude

March Standard Library Prelude

Everything in this module is auto-imported into every March program. These are the most commonly needed functions and types.

Sections:

  1. Diverging (panic, todo, unreachable)
  2. Option helpers
  3. Result helpers
  4. List basics
  5. Combinators (identity, compose, flip, const)
  6. String helpers

Naming overlap with module-qualified APIs is intentional:

  • head, tail, is_nil, length, reverse, fold_left,
`filter`, `map` are all List-typed in the prelude (their
signatures fix `xs : List(a)`), so `length(xs)` always means
`List.length(xs)`.  Strings have no `length` — use
`String.byte_size` / `String.codepoint_count` instead.  The
absence of a generic `length` prevents silent type confusion.
  • unwrap and unwrap_or operate on Option(a). For Result
call `Result.unwrap` directly.

New code should prefer module-qualified calls for readability; prelude names exist for short scripts and for the few cases (head, tail, length, reverse) where the unqualified name reads better. Prelude functions are called unqualified (length(xs), not Prelude.length(xs)).

Functions

fncomposecompose(f : b -> c, g : a -> b) : a -> c#

Function composition: returns the function fn x -> f(g(x)) (g runs first). March has no chained call f(a)(b), so bind the result or wrap it in parentheses before calling it.

Examples

march> (compose(fn x -> x * 2, fn x -> x + 1))(3)
8
march> List.map([1, 2], compose(fn x -> x * 2, fn x -> x + 1))
[4, 6]
fnconstconst(x : a) : b -> a#

Returns a one-argument function that always returns x, ignoring its argument.

Examples

march> List.map([1, 2, 3], const(0))
[0, 0, 0]
fndebugdebug(x)#

Prints a value using its Show representation, with a trailing newline, and returns (). The same output as println.

debug(Some(3))      -- prints Some(3)
fnfilterfilter(xs : List(a), pred : a -> Bool[p]) : List(a[p])#

Returns only the elements satisfying pred, in their original order.

Every element of the result is known to satisfy pred (an abstract refinement p, as for List.filter): with sum_pos(xs : List({Int | _ > 0})), sum_pos(filter(ys, fn y -> y > 0)) is proved.

Examples

march> filter([1, 2, 3, 4], fn x -> x > 2)
[3, 4]
fnflipflip(f : a -> b -> c) : b -> a -> c#

Flips the order of a two-argument function's arguments: the result g satisfies g(b, a) == f(a, b).

Examples

march> (flip(fn (a, b) -> a - b))(1, 10)
9
fnfold_leftfold_left(xs : List(a), acc : b, f : b -> a -> b) : b#

Left fold over a list. Argument order: collection first, init second, callback last (uncurried-collection convention). The callback takes the accumulator first: f(acc, x).

Examples

march> fold_left([1, 2, 3], 10, fn (acc, x) -> acc - x)
4
march> fold_left([], 10, fn (acc, x) -> acc - x)
10
fnheadhead(xs : {List(a) | len(_) > 0}) : a#

Returns the first element of the list. Panics if empty; use List.head_opt when the list may be empty.

Examples

march> head([4, 5])
4
fnidentityidentity(x : a) : a#

The identity function — returns its argument unchanged.

Examples

march> identity(5)
5
march> List.filter_map([Some(1), None, Some(3)], identity)
[1, 3]
fninspectinspect(x) do to_string(x) end#

Converts any value to its string representation; the same as str and to_string.

Examples

march> inspect([Some(1), None])
"[Some(1), None]"
march> inspect("hi")
"hi"
fnis_nilis_nil(xs : List(a)) : Bool#

Returns true if the list is empty.

Examples

march> is_nil([])
true
march> is_nil([1])
false
fnlengthlength(xs : List(a)) : Int#

Returns the number of elements in the list. O(n). Lists only: for a String use String.byte_size or String.codepoint_count.

Examples

march> length([1, 2, 3])
3
march> length([])
0
fnmapmap(xs : List(a), f : a -> b) : List(b)#

Applies f to every element of the list, returning the new list.

Examples

march> map([1, 2, 3], fn x -> x + 1)
[2, 3, 4]
march> map([], fn x -> x + 1)
[]
fnpanicpanic(msg : String) : a#

Terminates the program with a runtime error carrying msg. Used for violated invariants — bugs, not expected failures; return a Result for errors a caller can handle. Propagates to the enclosing actor boundary. Typechecks as any type, so it can stand in any branch:

fn safe_div(a : Int, b : Int) : Int do
  if b == 0 do panic("safe_div: zero divisor") else a / b end
end
fnprintlnprintln(x)#

Prints any Show value followed by a newline, and returns (). Works for Int, Float, String, Bool, List, Option, Result, tuples, and any type with an explicit impl Show. A String prints without quotes.

println([1, 2])     -- prints [1, 2]
println("hi")       -- prints hi
fnreversereverse(xs : List(a)) : List(a)#

Reverses a list.

Examples

march> reverse([1, 2, 3])
[3, 2, 1]
fnstrstr(x) do to_string(x) end#

Short alias for to_string: the value's Show representation. Strings nested inside a list, option or tuple are shown without quotes.

Examples

march> str(42)
"42"
march> str([1, 2])
"[1, 2]"
march> str(Some(true))
"Some(true)"
fntailtail(xs : {List(a) | len(_) > 0}) : List(a)#

Returns all but the first element. Panics if empty; use List.tail_opt when the list may be empty.

Examples

march> tail([4, 5])
[5]
march> tail([4])
[]
fntodotodo(msg : String) : a#

Marks code as not yet implemented: evaluating it is a runtime error carrying msg. Typechecks as any type so you can sketch a program top-down. Never valid in production.

fn parse_config(s : String) : Config do
  todo("parse_config")
end
fnunreachableunreachable() : a#

Asserts that a code path is unreachable: reaching it at runtime is an error. Typechecks as any type.

match n % 2 do
0 -> "even"
1 -> "odd"
_ -> unreachable()
end
fnunwrapunwrap(opt : {Option(a) | is_Some(_)}) : a#

Extracts the value from Some(x), panicking if None. The Option-only prelude form of Option.unwrap; for Result use Result.unwrap.

Examples

march> unwrap(Some(3))
3
fnunwrap_orunwrap_or(opt : Option(a), default : a) : a#

Returns the contained value, or default if None. Option-only; for Result use Result.unwrap_or.

Examples

march> unwrap_or(Some(1), 7)
1
march> unwrap_or(None, 7)
7
fnwith_capwith_cap(_c, f) do f(()) end#

Runs f with c installed as the capability its operations dispatch through, so a test can substitute an implementation:

with_cap(mock, fn _ -> code_under_test())

At runtime this simply calls f — the capability is consumed by the compiler's capability-passing elaboration, which rewrites calls inside f to route through c's dictionary. Outside a --test build the elaboration does not run and this is exactly f(()).

Examples

march> with_cap(0, fn _ -> 9)
9