rs-0.13.0 ā Algorithms, statistics, and memory#
Three new standard packages, all reachable now that functions can be passed
around: sorting and searching in std.algorithms,
descriptive statistics in std.stats, and object identity
in std.memory. @Decorator.private also applies to a
package's own functions and families.
std.algorithms#
takepkg std.algorithms;
func m{
people = arr(Person("Ada", 36), Person("Grace", 45), Person("Alan", 41));
for (p, algorithms.sort_by(people, func(Person p) => p.age)){ slout(p.name + " "); }
out(""); // Ada Alan Grace
out(algorithms.transform(arr(1, 2, 3), func(int x) => x * x)); // [1, 4, 9]
out(algorithms.counts(arr("fig", "pear", "fig"))); // {"fig": 2, "pear": 1}
}
sorted, sort_by, and sort_with are stable and O(n log n) for every input.
sort_by sorts the keys with the interpreter's own sort and regroups, so the
comparisons stay native and it runs about five times faster than a comparator
sort. sort_with, which must run Marslang code for each comparison, finds runs
that are already ordered, the way Timsort
does, and insertion-sorts below 16 items, the threshold
pdqsort and introsort use: an array that is
already in order costs one pass, and no input drops it to O(n²).
Also binary_search, lower_bound, upper_bound, transform, keep,
fold, min_by, max_by, any_of, all_of, unique, counts, and
group_by.
std.stats#
takepkg std.stats;
func m{
marks = arr(2, 4, 4, 4, 5, 5, 7, 9);
out(stats.mean(marks), stats.median(marks), stats.mode(marks)); // 5 4.5 4
out(stats.stdev(marks)); // 2.138089935299395
out(stats.quantile(marks, 0.25)); // 4
}
mean, median, mode, quantile, sum, variance, pvariance, stdev,
pstdev, covariance, and correlation. Sums are compensated, so
stats.sum(arr(0.1, 0.2, 0.3)) is 0.6 where adding left to right gives
0.6000000000000001. Variance is computed in two passes, which keeps its
digits where the one-pass form loses them, and quantiles interpolate as NumPy
and R type 7 do. Every result in the tests is checked against Python's
statistics module and NumPy.
std.memory#
takepkg std.memory;
func m{
a = arr(1, 2);
b = a;
out(memory.same(a, b), memory.same(a, arr(1, 2))); // true false
out(memory.pointer(a)); // array@0x1e248d94d30
cycle = arr(); cycle.add(cycle); cycle = null;
out(memory.collect()); // 1
}
address and pointer say where a value lives, same whether two names hold
one object, refs how many references keep it alive, and collect runs the
cycle collector and reports what it freed. Numbers, booleans, and null live
inside the value itself and have no address, which the error says.
There is no alloc or free: Marslang frees values by itself, so manual
allocation would teach C's habits without C's reason for them. An address is
for telling objects apart and for debugging, never for reaching back into
memory, and it means nothing between two runs.
Private package declarations#
@Decorator.private used to be a compile error above a function or family
outside a family. It now means the one thing it can mean there: the package
does not export it.
takepkg std.Decorator;
@Decorator.private
func check(array values){ ... }
func mean(array values){ check(values); ... } // fine, same package
An importer asking for stats.check gets stats has no member 'check'. A
leading underscore still does the same, and marslang symbols now reports each
function's real access. @Decorator.subclass stays methods-only.
Validation#
cargo test passes 131 tests (13 unit, 117 execution, 1 memory) on Windows
Rust and on WSL-native Rust. Every example on the new documentation pages was
run against this build.