Quick Start
Install the umbrella package:
gleam add lattice_crdtThis gives you all lattice packages. See Installation for individual package options.
Merge counters from multiple replicas
Section titled “Merge counters from multiple replicas”GCounter is the simplest place to start: each replica can only increase its
own contribution, and merging takes the per-replica maximum.
import lattice_core/replica_idimport lattice_counters/g_counter
pub fn main() { let counter_a = g_counter.new(replica_id.new("node-a")) |> g_counter.increment(2)
let counter_b = g_counter.new(replica_id.new("node-b")) |> g_counter.increment(3)
let merged = g_counter.merge(counter_a, counter_b)
g_counter.value(merged) // -> 5}g_counter.increment rejects negative deltas. If you need a counter that can
go down, use pn_counter from lattice_counters; both increment and
decrement still take non-negative deltas because the underlying state is
grow-only.
Resolve ties deterministically with LWW registers
Section titled “Resolve ties deterministically with LWW registers”LWWRegister stores a value plus a timestamp. Newer timestamps win. If two
replicas write at the same timestamp, lattice breaks the tie deterministically
using the replica ID.
import lattice_core/replica_idimport lattice_registers/lww_register
pub fn main() { let left = lww_register.new("apple", 7, replica_id.new("node-a")) let right = lww_register.new("zebra", 7, replica_id.new("node-b"))
let merged = lww_register.merge(left, right)
lww_register.value(merged) // -> "zebra" (node-b > node-a lexicographically)}lww_register.set only applies when the new timestamp is strictly greater than
the current one.
Store CRDT values inside an OR-Map
Section titled “Store CRDT values inside an OR-Map”ORMap tracks keys with add-wins semantics and stores a CRDT value at each
key. The CrdtSpec you choose when creating the map determines the default
value used when or_map.update sees a missing key.
import lattice_core/replica_idimport lattice_counters/g_counterimport lattice_maps/crdtimport lattice_maps/or_map
fn add_points(value: crdt.Crdt, delta: Int) -> crdt.Crdt { case value { crdt.CrdtGCounter(counter) -> crdt.CrdtGCounter(g_counter.increment(counter, delta))
other -> other }}
pub fn main() { let scoreboard_a = or_map.new(replica_id.new("node-a"), crdt.GCounterSpec) |> or_map.update("alice", fn(value) { add_points(value, 2) })
let scoreboard_b = or_map.new(replica_id.new("node-b"), crdt.GCounterSpec) |> or_map.update("alice", fn(value) { add_points(value, 3) })
let assert Ok(merged) = or_map.merge(scoreboard_a, scoreboard_b)
case or_map.get(merged, "alice") { Ok(crdt.CrdtGCounter(counter)) -> g_counter.value(counter) _ -> 0 } // -> 5}For more detail, see the Counters guide, Registers guide, Sets guide, and Maps guide.