March Docs

Seq

Seq module: lazy fold-based sequences (church-encoded). Seq(a) wraps fn(b, fn(b, a) -> b) -> b. Enum operates eagerly on Lists; Seq operates lazily over I/O or generated sequences.

Transformations (map, filter, take, ...) only build a new fold; nothing runs until a consumer (to_list, fold, count, find, ...) folds the sequence. Every fold visits the whole source: take, find, any, all and fold_while stop using elements early but never stop the iteration itself, so they do not terminate on an unbounded source (an unfold whose next never returns None). Bound such sources with unfold_until, repeat or iterate.

march> let evens = Seq.filter(Seq.from_list([1, 2, 3, 4, 5, 6]), fn x -> x % 2 == 0)
march> Seq.to_list(Seq.map(evens, fn x -> x * 10))
[20, 40, 60]

Types

ptypeStepStep(a) = Continue(a) | Halt(a)#

Step type for fold_while: Continue to keep folding, Halt to stop early.

ptypeSeqSeq(a) = Seq(a)#

Seq wraps a closure. March's type syntax cannot express the rank-2 type, so we omit the type annotation — the constructor takes any value (the fold fn).

Functions

fnallall(seq, pred)#

True if every element satisfies pred; true for an empty seq. pred is not called again after the first failure, but the whole seq is still visited.

Examples

march> Seq.all(Seq.from_list([1, 2, 3]), fn x -> x > 0)
true
march> Seq.all(Seq.empty(), fn x -> x > 0)
true
fnanyany(seq, pred)#

True if any element satisfies pred; false for an empty seq. pred is not called again after the first match, but the whole seq is still visited.

Examples

march> Seq.any(Seq.from_list([1, 2, 3]), fn x -> x > 2)
true
march> Seq.any(Seq.empty(), fn x -> x > 2)
false
fnbatchbatch(seq, n : {Int | _ > 0})#

Groups elements into lists of n (which must be positive); the last batch holds the remainder and may be shorter. An empty seq yields no batches.

Examples

march> Seq.to_list(Seq.batch(Seq.from_list([1, 2, 3, 4, 5]), 2))
[[1, 2], [3, 4], [5]]
march> Seq.to_list(Seq.batch(Seq.empty(), 2))
[]
fnbatchedbatched(seq, n : {Int | _ > 0})#

Alias for batch: groups elements into lists of size n. Provided for parity with the API name used by the spec/plan; batch remains the canonical name.

march> Seq.to_list(Seq.batched(Seq.from_list([1, 2, 3, 4, 5]), 2))
[[1, 2], [3, 4], [5]]
fnconcatconcat(s1, s2)#

The elements of s1 followed by the elements of s2.

Examples

march> Seq.to_list(Seq.concat(Seq.from_list([1, 2]), Seq.from_list([3])))
[1, 2, 3]
fncountcount(seq)#

The number of elements in the seq.

Examples

march> Seq.count(Seq.from_list([1, 2, 3]))
3
march> Seq.count(Seq.empty())
0
fncyclecycle(seq, n)#

Concatenate seq with itself n times. cycle(seq, 0) is empty.

Because Seq is church-encoded the underlying source is re-folded once per cycle; do not pass a one-shot source like from_file_lines (each re-fold would attempt to re-read a closed fd).

march> Seq.to_list(Seq.cycle(Seq.from_list([1, 2]), 3))
[1, 2, 1, 2, 1, 2]
fndropdrop(seq, n)#

All but the first n elements (empty if n >= length; the whole seq if n <= 0).

Examples

march> Seq.to_list(Seq.drop(Seq.from_list([1, 2, 3]), 2))
[3]
march> Seq.to_list(Seq.drop(Seq.from_list([1, 2, 3]), 5))
[]
fneacheach(seq, f)#

Calls f on each element for its side effects and returns :ok. f's result is discarded, but the current typing threads it as the accumulator, so f must return an Atom (e.g. :ok).

Seq.each(Seq.from_list(["a", "b"]), fn s -> do
  println(s)
  :ok
end)
fnemptyempty()#

The empty seq: folding it returns the start accumulator unchanged.

Examples

march> Seq.to_list(Seq.empty())
[]
march> Seq.count(Seq.empty())
0
fnfilterfilter(seq, pred)#

Lazily keeps only the elements for which pred returns true.

Examples

march> Seq.to_list(Seq.filter(Seq.from_list([1, 2, 3, 4]), fn x -> x % 2 == 0))
[2, 4]
fnfindfind(seq, pred)#

The first element satisfying pred as Some, or None. Built on fold_while, so the whole seq is still visited.

Examples

march> Seq.find(Seq.from_list([1, 2, 3, 4]), fn x -> x > 2)
Some(3)
march> Seq.find(Seq.from_list([1, 2]), fn x -> x > 5)
None
fnflat_mapflat_map(seq, f)#

Lazily applies f (which returns a Seq) to each element and concatenates the resulting seqs.

Examples

march> Seq.to_list(Seq.flat_map(Seq.from_list([1, 2]), fn x -> Seq.from_list([x, x])))
[1, 1, 2, 2]
fnfoldfold(seq, start, f)#

Folds the seq left to right: f(acc, x) returns the next accumulator, starting from start. Returns start for an empty seq.

Examples

march> Seq.fold(Seq.from_list([1, 2, 3]), 0, fn (acc, x) -> acc + x)
6
march> Seq.fold(Seq.empty(), 5, fn (acc, x) -> acc + x)
5
fnfold_whilefold_while(seq, start, f)#

Folds with early exit: f(acc, x) returns Continue(acc2) to keep going or Halt(result) to stop accumulating; the result is the last Continue/Halt payload. The remaining elements are still visited (and ignored) after a Halt, so this does not terminate on an unbounded seq.

Examples

march> Seq.fold_while(Seq.from_list([1, 2, 3, 4]), 0, fn (acc, x) -> if acc + x > 5 do Halt(acc) else Continue(acc + x) end)
3
fnfrom_file_chunksfrom_file_chunks(path, size)#

Open path and return a lazy Seq(Bytes) of fixed-size chunks. The final chunk may be shorter than size if the file does not divide evenly. Returns Ok(seq) or Err(file_error). The fd is closed on EOF, so consume to completion (to_list, fold, etc.).

fnfrom_file_linesfrom_file_lines(path)#

Open path and return a lazy Seq(String) over its lines. Returns Ok(seq) on success or Err(file_error) on failure. The file handle is closed automatically when iteration reaches EOF; consume the seq fully (or via to_list) to release the fd.

Each line is yielded with its trailing newline stripped.

match Seq.from_file_lines("data.txt") do
Ok(s) -> Seq.to_list(Seq.take(s, 10))     -- first 10 lines
Err(_) -> []
end
fnfrom_listfrom_list(xs)#

A seq over the elements of a list, in order.

Examples

march> Seq.to_list(Seq.from_list([1, 2, 3]))
[1, 2, 3]
fnfrom_string_linesfrom_string_lines(s)#

Build a Seq(String) from a string by splitting on "\\n" (a "\\r" before it is kept). Trailing empty lines are dropped, so neither "a\\nb\\n" nor "a\\nb\\n\\n" produces a final ""; blank lines in the middle are preserved. The empty string yields an empty seq.

Examples

march> Seq.to_list(Seq.from_string_lines("a\nb\n"))
["a", "b"]
march> Seq.to_list(Seq.from_string_lines("a\n\nb"))
["a", "", "b"]
march> Seq.to_list(Seq.from_string_lines(""))
[]
fniterateiterate(seed, step, n)#

Apply step repeatedly starting from seed, yielding n elements: [seed, step(seed), step(step(seed)), …]. iterate(_, _, 0) is empty.

march> Seq.to_list(Seq.iterate(1, fn x -> x * 2, 5))
[1, 2, 4, 8, 16]
fnmapmap(seq, f)#

Lazily applies f to each element. f runs once per element each time the result is folded.

Examples

march> Seq.to_list(Seq.map(Seq.from_list([1, 2, 3]), fn x -> x * 10))
[10, 20, 30]
fnrepeatrepeat(x, n)#

A Seq(a) that yields x exactly n times. repeat(_, 0) is the empty seq; negative n is treated as 0.

march> Seq.to_list(Seq.repeat("hi", 3))
["hi", "hi", "hi"]
march> Seq.to_list(Seq.repeat(7, -2))
[]
fntaketake(seq, n)#

The first n elements (all of them if there are fewer; none if n <= 0). The source is still folded to its end, the extra elements just ignored, so take does not make an unbounded seq finite: use unfold_until.

Examples

march> Seq.to_list(Seq.take(Seq.from_list([1, 2, 3]), 2))
[1, 2]
march> Seq.to_list(Seq.take(Seq.from_list([1, 2, 3]), 0))
[]
fnto_listto_list(seq)#

Folds the seq into a list, in order.

Examples

march> Seq.to_list(Seq.map(Seq.from_list([1, 2]), fn x -> x + 1))
[2, 3]
fnunfoldunfold(seed, next)#

A seq generated from seed: next(seed) returns Some((value, seed2)) to yield value and continue from seed2, or None to stop. next is re-run from seed every time the seq is folded. If next never returns None the seq is unbounded and no consumer terminates on it (see unfold_until).

Examples

march> Seq.to_list(Seq.unfold(1, fn n -> if n > 4 do None else Some((n, n + 1)) end))
[1, 2, 3, 4]
fnunfold_untilunfold_until(seed, next, max)#

Like unfold but with an upper bound on the number of elements produced. Stops at the smaller of (a) next returning None or (b) max elements yielded.

march> let s = Seq.unfold_until(0, fn n -> Some((n, n + 1)), 5)
march> Seq.to_list(s)
[0, 1, 2, 3, 4]
fnzipzip(s1, s2)#

Pairs elements of s1 with elements of s2, stopping at the shorter one. s2 is materialised to a list (via to_list) each time the result is folded, so it must be finite; s1 drives the iteration.

Examples

march> Seq.to_list(Seq.zip(Seq.from_list([1, 2, 3]), Seq.from_list(["a", "b"])))
[(1, "a"), (2, "b")]