Real-World Examples
Practical patterns you can copy and adapt. Each example is a complete, runnable program.
Data pipeline
Section titled “Data pipeline”Fetch JSON from an API, filter positive values, sum them:
fetch url:t>R _ t;r=get! url;rdb! r "json"pos x:_>b;>x 0proc rows:L _>n;clean=flt pos rows;sum cleanThree functions, no boilerplate. $! auto-unwraps the HTTP response. rdb! parses JSON. flt keeps only elements where pos returns true.
API status checker
Section titled “API status checker”Hit a URL and report whether it responded:
check url:t>t r=get url ?r{~v:fmt "{}: ok" url;^e:fmt "{}: {}" url e}ilo 'check url:t>t;r=get url;?r{~v:fmt "{}: ok" url;^e:fmt "{}: {}" url e}' "http://httpbin.org/get"# -> http://httpbin.org/get: okget url makes an HTTP GET (since 0.12.0 the $ sigil is process exec, not HTTP). The result is matched: ~v (Ok) or ^e (Err).
CSV processing
Section titled “CSV processing”# Column count of the first rowilo 'f p:t>R n t;d=rd! p;~len d.0' f data.csvrd! reads and parses the CSV file (returns R, so the function must too). d.0 indexes the first row.
Text processing
Section titled “Text processing”Count unique words in a file:
ilo 'f p:t>R n t;t=rd! p "raw";ws=spl t " ";~len (unq ws)' f document.txtExtract all emails from text:
ilo 'f s:t>L t;rgx "[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}" s' \ "contact alice@example.com or bob@test.org"# -> [alice@example.com, bob@test.org]Sort words by length:
wlen s:t>n;len sby-len ws:L t>L t;srt wlen wsilo examples/sort-by-key.ilo by-len '["banana","fig","apple","kiwi"]'# -> ["fig", "kiwi", "apple", "banana"]Environment config
Section titled “Environment config”Read an env var with a fallback:
cfg>t k=env "API_KEY" ?k{~v:v;^e:"missing API_KEY"}env returns a Result. The match provides the value or a default.
Tool interaction
Section titled “Tool interaction”Declare external tools, then compose them like regular functions:
tool get-user"Retrieve user by ID" uid:t>R profile t timeout:5,retry:2tool send-email"Send notification email" to:t subject:t body:t>R _ t timeout:10,retry:1
type profile{id:t;name:t;email:t;verified:b}
notify uid:t msg:t>R _ t u=get-user! uid !u.verified{^"user not verified"} send-email! u.email "Notification" msg ~nilTools are type-checked at compile time. get-user! unwraps the result, propagating errors automatically.
Python vs ilo
Section titled “Python vs ilo”A tax-inclusive total calculation in both languages.
Python (93 chars, ~30 tokens):
def total(price: float, quantity: int, rate: float) -> float: sub = price * quantity tax = sub * rate return sub + taxilo (38 chars, ~10 tokens):
tot p:n q:n r:n>n;s=*p q;t=*s r;+s tSame semantics. 0.33x the tokens, 0.22x the characters. For an AI agent paying per token, this adds up fast across thousands of tool calls.
Sum types
Section titled “Sum types”Classify HTTP status codes using a discriminated union:
type status = ok(n) | redirect(n) | err(t)
describe s:status>t;?s{ok(code):fmt "OK {}" code; redirect(code):fmt "redirect {}" code; err(msg):fmt "error: {}" msg}Parallel processing
Section titled “Parallel processing”Double 10 000 numbers in parallel:
ilo 'double x:n>n;*x 2 main>L n;par-map double (range 0 10000)' maindefer for cleanup
Section titled “defer for cleanup”Read a file and guarantee close on exit:
read-lines path:t>R L t t f = open! path defer close f ~rdl! fError chaining with !
Section titled “Error chaining with !”The ! unwrap operator keeps fallible pipelines flat - each step propagates its error automatically, no nesting:
row-total r:L t>R n t;~num! r.0
process path:t>R n t rows=rd! path totals=mapr row-total rows ~sum totalsPagination (tail-recursive accumulator)
Section titled “Pagination (tail-recursive accumulator)”Canonical pattern for iterating paged APIs: tail-recursive accumulator + empty-token termination + Result chain (! propagation). No stack growth regardless of page count.
-- fetch-page: one HTTP call; returns ~[items next-token] or Err.fetch-page url:t token:t>R (L _) t b=get! (fmt "{}&cursor={}" url token) items=jpar-list! b nxt=default-on-err (jpth b "next_cursor") "" ~[items nxt]
-- fetch-all: tail-recursive; empty token signals end-of-pages.fetch-all url:t token:t acc:L n>R (L n) t =token "" ~acc r=fetch-page! url token page=at r 0 nxt=at r 1 fetch-all url nxt +acc page
-- Entry: seed with empty token and empty accumulator.all-items>R (L n) t fetch-all "https://api.example.com/items" "" []The fld builtin threads a numeric accumulator if you want a running total instead of collecting all items:
sum-all>R n t xs=fetch-all! "https://api.example.com/items" "" [] ~fld (a:n x:n>n;+a x) xs 0What’s next
Section titled “What’s next”- Run
ilo -aito get the compact spec for your AI agent - Read the full language specification
- Browse example programs
- Try the REPL:
ilo repl