Skip to main content

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 liftingshift_port(10000, ports) applies the same scalar function to every field of the object. No explicit traversal code is needed.
  • Broadcast over structured valuesscale(3, replica_counts) keeps the scalar 3 fixed while lifting across the object on the right.
  • Zipped list liftingadd(base_ports, rollout_offsets) aligns both lists by position and applies add element-by-element.
  • with patchbase_service with { debug: true } produces a new object identical to base_service except for the overridden fields. The original is never mutated.

Run it

rank examples/functions-and-lifting