Skip to content

Scatter-Gather

Scatter: spawn one actor per input using builtins.map. Gather: collect all outboxes into one stream using merge.

flowchart TB
  inputs["inputs [5, -1, 8, 0, 2]"]
  a1["validator-c {inbox=st 5}"]
  a2["validator-c {inbox=st -1}"]
  a3["validator-c {inbox=st 8}"]
  a4["validator-c {inbox=st 0}"]
  a5["validator-c {inbox=st 2}"]
  m["merge"]
  out["results ST"]

  inputs -->|"builtins.map"| a1 & a2 & a3 & a4 & a5
  a1 & a2 & a3 & a4 & a5 -->|"outbox"| m
  m --> out
inherit (dnzl) merge actor reply;
inherit (dnzl.ned) st;
validator = n:
if n > 0 then reply.right n
else reply.left "non-positive: ${toString n}";
validator-c = actor validator;
inputs = [ 5 (-1) 8 0 2 ];
actors = builtins.map (n: validator-c { inbox = st n; }) inputs;
results = merge (builtins.map (a: a.outbox) actors);
results.toList
# [ { right = 5; }
# { left = "non-positive: -1"; }
# { right = 8; }
# { left = "non-positive: 0"; }
# { right = 2; } ]

Results appear in input order because merge concatenates streams in list order. Each actor is independent — no shared state.

Apply .right after merge to collect only the successful results:

all = merge (builtins.map (a: a.outbox) actors);
all.right.toList
# [ 5 8 2 ]

Different actors for different inputs — the pattern is the same:

ops = [
{ ref = validator-c; input = 5; }
{ ref = div-c; input = { dividend = 10; divisor = 2; }; }
{ ref = validator-c; input = (-3); }
];
actors = builtins.map (op: op.ref { inbox = st op.input; }) ops;
results = merge (builtins.map (a: a.outbox) actors);

Each actor processes its own slice in isolation. The caller chooses which ref handles each input.

Contribute Community Sponsor