Functions and Lifting
First-class functions, object and list lifting, and non-destructive override with with.
Source
examples/functions-and-lifting/main.rank
/// Demonstrates first-class functions, automatic lifting over lists and objects,
/// zipped list lifting, and the `with` patch operator.
shift_port = |delta: number, port: number| -> number {
return port + delta
}
scale = |factor: number, value: number| -> number {
return value * factor
}
add = |left: number, right: number| -> number {
return left + right
}
ports = {
api: 8080,
worker: 9090,
admin: 7070,
}
replica_counts = {
api: 3,
worker: 2,
admin: 1,
}
base_ports = [8080, 8081, 8082]
rollout_offsets = [0, 100, 200]
base_service = {
port: 3000,
replicas: 1,
debug: false,
}
dev_override = base_service with {
debug: true,
}
prod_override = base_service with {
replicas: 5,
}
pub main = || {
shifted_ports: shift_port(10000, ports),
scaled_replicas: scale(3, replica_counts),
canary_ports: add(base_ports, rollout_offsets),
dev: dev_override,
prod: prod_override,
}
Output
{
"shifted_ports": {
"api": 18080,
"worker": 19090,
"admin": 17070
},
"scaled_replicas": {
"api": 9,
"worker": 6,
"admin": 3
},
"canary_ports": [8080, 8181, 8282],
"dev": {
"port": 3000,
"replicas": 1,
"debug": true
},
"prod": {
"port": 3000,
"replicas": 5,
"debug": false
}
}
Key concepts
- Object lifting —
shift_port(10000, ports)applies the same scalar function to every field of the object. No explicit traversal code is needed. - Broadcast over structured values —
scale(3, replica_counts)keeps the scalar3fixed while lifting across the object on the right. - Zipped list lifting —
add(base_ports, rollout_offsets)aligns both lists by position and appliesaddelement-by-element. withpatch —base_service with { debug: true }produces a new object identical tobase_serviceexcept for the overridden fields. The original is never mutated.
Run it
rank examples/functions-and-lifting