List Callbacks and Transformations

List callbacks let a query inspect or transform each element without adding a general-purpose function language. Callback parameters are inferred from the list and are scoped to the callback expression. The full rules are in the method reference and type specification.

Select and check elements

items:any(item=>item.price>100)
items:all(item=>item.available)
orders:any(order=>order.active order.items:any(item=>item.price>10))
items:any(item=>item.active | item.price>10)

any() is true when at least one callback result converts to true; all() is true when every result converts to true. Both visit from left to right and stop once the answer is known. An empty list returns false for any() and true for all(). A null receiver returns null. A guarded no-value callback result converts to false for that element; cancellation and limit errors remain errors.

Transform and fold

items:map(item=>item.name)=["Book","Pen"]
items:flatmap(item=>[item.name])=["Book","Pen"]
items:foldl(0,(total,item)=>total+item.price)>100
items:foldr("",(item,tail)=>item.name:concat(tail))="BookPen"

map() visits left to right and preserves ordinary null results as list elements. flatmap() also visits left to right and appends each returned list; a callback result that is dynamically not a list makes the whole result null. Guarded no-value from either transformation propagates to the whole call.

foldl(initial,(acc,item)=>expr) visits left to right, while foldr(initial,(item,acc)=>expr) visits right to left. Both return the initial accumulator for an empty list. The accumulator type includes the initial value and possible callback results; a null result becomes the next accumulator, and guarded no-value propagates to the entire fold.

Callback parameters use lexical scope and may capture unshadowed outer schema variables and outer callback parameters. Parameter names may shadow an outer name. Nested callbacks keep their own parameter bindings. AND and OR retain left-to-right short-circuit behavior inside callbacks; in the nested example, the inner list is examined only for active orders. Nested callbacks require the NestedCallbacks capability, which depends on Callbacks. MaxCallbackDepth defaults to 64, counting the outermost callback as depth 1. Callback expressions cannot call general user-defined functions or perform side effects.

Run the example

The example uses a list of products to select, check, map, and fold:

go run ./examples/callbacks

Expected output:

items:any(item=>item.price>100) -> true
items:all(item=>item.available) -> false
items:map(item=>item.name)=["Book","Pen"] -> true
items:foldl(0,(total,item)=>total+item.price)>100 -> true

Local evaluation applies the per-match step and generated-value budgets and checks context cancellation while traversing callbacks. An error aborts the match without returning a partial result; see the local backend guide for configuration.

Explore HFF
Search documentation

Search the language specification and guides.