ilo 26.5.0

ilo - the token-minimal programming language AI agents write
Documentation
-- Canonical pagination idiom (ILO-421, supersedes ILO-88).
--
-- Pattern: tail-recursive accumulator + empty-token termination + Result chain.
--
-- Shape:
--   fetch-all url token acc
--     token="" → ~acc              (done: wrap and return)
--     page,next = fetch-page url token
--     fetch-all url next (+acc page)  (tail position — no stack growth)
--
-- `fld` threads the accumulator for in-memory aggregation once all pages
-- are collected.  The Result chain (`!` propagation) means any HTTP or
-- parse Err bubbles up from `fetch-page` without explicit match arms.

-- ---------------------------------------------------------------------------
-- Simulated paged data source.
-- Real code would call `get!` / `pst!` here; we return hardcoded pages so
-- the example runs without network access and passes on every engine.
-- Tokens: "0"→page0 (next "1"), "1"→page1 (next "2"), "2"→page2 (next ""),
-- where "" signals end-of-pages.  In a real API the server supplies tokens.
-- ---------------------------------------------------------------------------

-- page-data: returns [items, next-token] for a given 0-based page index n.
page-data idx:n>L _
  ?idx{
    0:[[1 2] "1"]
    1:[[3 4] "2"]
    2:[[5 6] ""]
    _:[[]]
  }

-- fetch-page: simulates a network call returning a Result-wrapped record.
-- Returns ~[items next-token] (Ok) or ^"out of range" (Err).
-- In a real program: b=get! url; items=jpar-list! b; nxt=default-on-err (jpth b "next") ""; ~[items nxt]
fetch-page url:t token:t>R (L _) t
  idx=default-on-err (num token) 0
  r=page-data idx
  =len r 0 ^"out of range"
  items=at r 0
  nxt=at r 1
  ~[items nxt]

-- ---------------------------------------------------------------------------
-- Core idiom: tail-recursive paginator.
-- Empty string token signals the last page has been consumed.
-- ---------------------------------------------------------------------------

fetch-all url:t token:t acc:L n>R (L n) t
  -- termination: empty next-token means we have collected all pages
  =token "" ~acc
  -- fetch this page (! propagates Err out of fetch-all)
  r=fetch-page! url token
  page=at r 0
  nxt=at r 1
  -- tail call with extended accumulator (no stack frame consumed)
  fetch-all url nxt +acc page

-- Entry points -----------------------------------------------------------

-- all-items: collect every item across pages, return as list.
all-items>R (L n) t
  fetch-all "https://api.example.com/items" "0" []

-- sum-pages: collect then fold to a sum (fld threads accumulator over result).
sum-pages>R n t
  xs=fetch-all! "https://api.example.com/items" "0" []
  ~fld (a:n x:n>n;+a x) xs 0

-- count-pages: count total items without keeping them all in memory.
-- Uses a dedicated tail-recursive counter to show the streaming variant.
count-all url:t token:t n:n>R n t
  =token "" ~n
  r=fetch-page! url token
  page=at r 0
  nxt=at r 1
  count-all url nxt +n len page

total-count>R n t
  count-all "https://api.example.com/items" "0" 0

-- run: all-items
-- out: [1, 2, 3, 4, 5, 6]

-- run: sum-pages
-- out: 21

-- run: total-count
-- out: 6