alm implements Elm 0.19.1; the fourth component is alm's own revision.
Compiler
- Incremental compilation, on by default — a
.alm-stuffper-module cache
that also caches the module graph, so a project is not re-read to rediscover
it. Cold builds, warm builds and no-op builds are all faster thanelm make;
a build with nothing to do is skipped outright. wasm-gc and native are
incremental too. - Faster type checking and monomorphization — structures are looked at
rather than copied, record rows are shared, integer keys hash with FxHash.
Monomorphization went from 2.66 s to 0.98 s on a 59k-line app, and is now
deterministic. - Byte-exact syntax errors — elm's whole parse-error catalogue ported, 89
differential fixtures, in plain text, in color and as--report=json. - Byte-exact type errors — elm's report machinery and pretty-printer,
including pattern reports, record contexts and ANSI coloring. --optimize,--docs=<file>,--report=json.- Subcommands:
init,install,diff,bump,publish,reactor,
repl. - Source maps for JS and wasm-gc (
--source-maps), with named function
expressions and block-scoped locals so call stacks and the debugger read
properly. - A performance hint for a keyed list built without
Html.Lazy. - Fixed record-alias constructors ignoring their declared field types.
Live reload
alm make --live serves the program, rebuilds on save and hot-swaps the new
build into the open page, keeping the running model when the new build still
agrees what a Model is. With --output it also writes the bundle, so a page
belonging to a larger app hot-swaps without knowing anything about alm.
alm reactor reloads the same way.
Runtime and backends
- Unrolled (chunked) lists on every target — allocation is amortized rather
than one cell per element. - Deforestation:
foldl/foldrof aList.mapcompiles to a single loop
with no intermediate list (7.6x on that chain). - Decision trees (Maranget) for nested
casepatterns with join-point
sharing, and jump tables for flat dispatch — a JSswitch, a wasm-gc
br_table. - vdom: attributes and events are diffed on patch instead of re-applied,
and the keyed reconciler has an allocation-free fast path for unchanged
order. - wasm-gc: unboxed scalar lists (Int, Char, Float), effect managers,
type-directed outgoing-port encoding, cross-module ports. - Effect modules —
Time,RandomandHttpare real bundled-source
effect modules on all three backends, and user-defined effect managers run
everywhere. - WebGL rendering kernel, including
WebGL.Texture.load. - elm/bytes on all three backends.
- Parity fixes: native
String.fromFloatexponent notation,String.lengthin
UTF-16 units,String.linesline endings,min/maxNaN semantics. - The LLVM-based wasm target is gone; the targets are
js,native,wasm-gc.
Benchmarks
make bench runs every harness and rebuilds bench-report/report.html:
a real-browser js-framework-benchmark harness, pure-computation workloads, and
compile speed against elm make on public projects.
Install
| binary | targets |
|---|---|
alm-0.19.1.1-macos-arm64.tar.gz |
js, wasm-gc, native |
alm-0.19.1.1-macos-x86_64.tar.gz |
js, wasm-gc, native |
alm-0.19.1.1-linux-x86_64.tar.gz |
js, wasm-gc |
alm-0.19.1.1-linux-arm64.tar.gz |
js, wasm-gc |
alm-0.19.1.1-windows-x86_64.zip |
js, wasm-gc |
--target=native is macOS-only for now: the runtime's conservative collector
finds its roots through Darwin interfaces, and the ELF equivalents are not
written yet. The other binaries are built without that backend and say so if
you ask for it — everything else is the same compiler.
From source: cargo build --release -p alm needs LLVM 16 and the pinned rustc
that produces matching bitcode; --no-default-features drops both and builds
the js and wasm-gc compiler anywhere a Rust toolchain runs.