Examples
A collection of XS code showing off various features.
FizzBuzz
The classic, with pattern matching.
fn fizzbuzz(n) {
match (n % 3, n % 5) {
(0, 0) => "FizzBuzz"
(0, _) => "Fizz"
(_, 0) => "Buzz"
_ => "{n}"
}
}
fn main() {
for i in 1..=100 {
println(fizzbuzz(i))
}
}Generators
Lazy sequences with fn* and yield.
fn* fibonacci() {
var a = 0
var b = 1
loop {
yield a
let tmp = a
a = b
b = tmp + b
}
}
fn main() {
for n in fibonacci() {
if n > 100 { break }
println(n)
}
}Tagged blocks
User-defined control structures.
-- retry a block up to n times
tag retry(n) {
var attempts = 0
loop {
try {
let result = yield
return result
} catch e {
attempts = attempts + 1
if attempts >= n {
throw "failed after {n} attempts: {e}"
}
}
}
}
retry(3) {
http.get("https://flaky-api.com")
}
-- measure execution time
tag timed() {
import time
let start = time.clock()
let result = yield
println("took {time.clock() - start}s")
return result
}
timed() {
heavy_computation()
}Error handling with effects
Recoverable errors without exceptions or Result types.
effect Fail {
fn fail(msg)
}
fn parse_int(s) {
for ch in s.chars() {
if not ch.is_digit() {
perform Fail.fail("not a number: {s}")
}
}
return s.parse_int()
}
fn main() {
let result = handle {
let n = parse_int("42")
let m = parse_int("abc")
n + m
} {
Fail.fail(msg) => {
println("error: {msg}")
resume(0)
}
}
println(result) -- 42
}Structs and operator overloading
Custom types with operators.
struct Vec2 { x, y }
impl Vec2 {
static fn new(x, y) {
return Vec2 { x: x, y: y }
}
fn +(self, other) {
return Vec2 { x: self.x + other.x, y: self.y + other.y }
}
fn magnitude(self) {
return sqrt(self.x * self.x + self.y * self.y)
}
}
fn main() {
let a = Vec2.new(3.0, 4.0)
let b = Vec2.new(1.0, 2.0)
let c = a + b
println("magnitude: {c.magnitude()}")
}List comprehensions
Concise collection transformations.
-- squares
let squares = [x * x for x in 0..10]
println(squares) -- [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
-- filtered
let evens = [x for x in 0..20 if x % 2 == 0]
println(evens) -- [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
-- map comprehension
let sq = #{x: x * x for x in [1, 2, 3, 4, 5]}
println(sq) -- {1: 1, 2: 4, 3: 9, 4: 16, 5: 25}
-- nested with destructuring
let pairs = [(x, y) for x in 0..3 for y in 0..3 if x != y]Inline C
Drop to C when you need raw performance.
fn fast_hash(data) {
inline c {
uint64_t h = 0x525201;
const char *s = xs_to_cstr(args[0]);
while (*s) h = h * 31 + *s++;
xs_return_int(h);
}
return 0 -- fallback for interpreter mode
}
fn main() {
println(fast_hash("hello world"))
}Nurseries
Structured concurrency with guaranteed cleanup.
let pipe = channel()
var output = []
nursery {
-- producer
spawn {
for i in 1..=5 {
pipe.send(i * 10)
}
}
-- consumer
spawn {
for i in 0..5 {
output.push(pipe.recv())
}
}
}
-- all tasks complete before we get here
println(output) -- [10, 20, 30, 40, 50]Reactive signals
Observable values that propagate changes.
let count = signal(0)
let doubled = derived(fn() { count.get() * 2 })
count.subscribe(fn(val) {
println("count changed to {val}")
})
count.set(5)
println(doubled.get()) -- 10
count.set(10)
println(doubled.get()) -- 20