Rayforce ← Back to home
GitHub

Complete Function Reference

Every one of the 170 built-in functions in Rayfall, organized by category. Each entry shows the function name, arity type, flags, a description, and an example.

Legend: atomic — auto-maps element-wise over vectors. aggr — reduces vectors to scalars (used in group-by). special — receives unevaluated arguments (special form). restricted — disabled in sandboxed mode.

Categories

Arithmetic (15)Comparison (7)Logic (3)
Aggregation (14)Higher-Order (12)Collection (19)
Sorting & Ordering (8)Control Flow & Special Forms (11)Table Operations (13)
Query (4)Joins (6)Pivot (1)
String (3)Temporal (3)Type & Introspection (5)
I/O & Output (12)System & Utility (15)Serialization (2)
Storage (3)IPC (3)EAV Triple Store (5)
Datalog (2)Datalog Program API (6)

Arithmetic

All arithmetic operators are atomic — they auto-map over vectors and broadcast scalars.

FunctionTypeFlagsDescriptionExample
+binaryatomicAddition(+ 3 4)7
-binaryatomicSubtraction(- 10 3)7
*binaryatomicMultiplication(* 3 4)12
/binaryatomicInteger division (floor)(/ 7 2)3
%binaryatomicModulo (remainder)(% 7 3)1
divbinaryatomicFloat division (always returns f64)(div 7 2)3.5
negunaryatomicNegate value(neg 5)-5
roundunaryatomicRound to nearest integer(round 3.7)4.0
floorunaryatomicFloor (round down)(floor 3.7)3.0
ceilunaryatomicCeiling (round up)(ceil 3.2)4.0
absunaryatomicAbsolute value(abs -7)7
sqrtunaryatomicSquare root (returns f64)(sqrt 9)3.0
logunaryatomicNatural logarithm(log 2.718)~1.0
expunaryatomicExponential (e^x)(exp 1)2.718...
xbarbinaryatomicRound down to nearest multiple (bucketing)(xbar [3 7 12] 5)[0 5 10]
; Vector arithmetic — atomic ops broadcast scalars
(+ [1 2 3] [10 20 30])   ; [11 22 33]
(* [1 2 3] 10)            ; [10 20 30]  scalar broadcast
(abs [-3 0 5])              ; [3 0 5]
(sqrt [4 9 16])             ; [2.0 3.0 4.0]

; Time bucketing for OHLC bars
(xbar [3 15 27] 10)        ; [0 10 20]

Comparison

All comparison operators are atomic and return boolean results.

FunctionTypeFlagsDescriptionExample
>binaryatomicGreater than(> 5 3)true
<binaryatomicLess than(< 3 5)true
>=binaryatomicGreater than or equal(>= 5 5)true
<=binaryatomicLess than or equal(<= 3 5)true
==binaryatomicEqual(== 3 3)true
!=binaryatomicNot equal(!= 3 4)true
withinbinaryCheck which elements fall within a [lo hi) range(within [1 5 10] [3 7])[false true false]
; Vector comparisons return boolean vectors
(> [10 20 30] 15)          ; [false true true]
(== [1 2 3] [1 0 3])       ; [true false true]

; within checks half-open range [lo, hi)
(within [1 3 5 7] [3 6])  ; [false true true false]

Logic

Boolean logic operators. Work on scalars and vectors alike.

FunctionTypeFlagsDescriptionExample
andbinaryLogical AND(and true false)false
orbinaryLogical OR(or true false)true
notunaryLogical NOT(not true)false
; Combine filters with logic ops
(and (> [1 5 3] 2) (< [1 5 3] 4))  ; [false false true]
(not [true false true])    ; [false true false]

Aggregation

Aggregation functions reduce vectors to scalar values. Functions marked aggr are recognized by the DAG executor for group-by operations.

FunctionTypeFlagsDescriptionExample
sumunaryaggrSum of all elements(sum [1 2 3])6
countunaryaggrCount of elements(count [1 2 3])3
avgunaryaggrArithmetic mean(avg [1 2 3])2.0
minunaryaggrMinimum value(min [3 1 2])1
maxunaryaggrMaximum value(max [3 1 2])3
firstunaryFirst element of a vector(first [10 20 30])10
lastunaryLast element of a vector(last [10 20 30])30
medunaryaggrMedian value(med [1 3 2])2
devunaryaggrSample standard deviation(dev [2 4 4 4 5 5 7 9])2.0
stddevunaryaggrSample standard deviation (alias of dev)(stddev [1 2 3])0.816...
stddev_popunaryaggrPopulation standard deviation(stddev_pop [1 2 3])
dev_popunaryaggrPopulation standard deviation (alias)(dev_pop [1 2 3])
varunaryaggrSample variance(var [1 2 3])1.0
var_popunaryaggrPopulation variance(var_pop [1 2 3])
; Basic aggregation
(sum [10 20 30])           ; 60
(avg [10 20 30])           ; 20.0
(med [1 100 5])            ; 5

; Group-by aggregation in select
(select {from: trades
         by:   {sym: sym}
         cols: {hi: (max price) lo: (min price) n: (count price)}})

Higher-Order Functions

Functions that take other functions as arguments for mapping, folding, and filtering.

FunctionTypeFlagsDescriptionExample
mapvariadicApply function to each element(map (fn [x] (* x 2)) [1 2 3])[2 4 6]
pmapvariadicParallel map (multi-threaded)(pmap (fn [x] (* x x)) [1 2 3])[1 4 9]
foldvariadicReduce with function and initial value(fold + 0 [1 2 3])6
fold-leftvariadicLeft-associative fold(fold-left - 10 [1 2 3])4
fold-rightvariadicRight-associative fold(fold-right - 10 [1 2 3])-8
scanvariadicRunning fold (all intermediate results)(scan + (enlist 1 2 3))[1 3 6]
scan-leftvariadicLeft-to-right running fold(scan-left + (enlist 1 2 3))[1 3 6]
scan-rightvariadicRight-to-left running fold(scan-right + (enlist 1 2 3))[6 5 3]
filterbinaryKeep elements where boolean mask is true(filter [1 2 3 4] (> [1 2 3 4] 2))[3 4]
applyvariadicZip-apply function pairwise over lists(apply + (enlist 1 2) (enlist 3 4))[4 6]
map-leftvariadicMap with left argument fixed(map-left + 10 [1 2 3])[11 12 13]
map-rightvariadicMap with right argument fixed(map-right - [10 20 30] 5)[5 15 25]
; Transform each row with map
(map (fn [x] (* x x)) [1 2 3 4])  ; [1 4 9 16]

; Parallel map for expensive computation
(pmap (fn [t] (sum (til t))) [100 200 300])

; Running sum with scan
(scan + (enlist 1 2 3 4))  ; [1 3 6 10]

Collection Operations

Operations on vectors and lists as collections — set operations, indexing, searching, and construction.

FunctionTypeFlagsDescriptionExample
distinctunaryRemove duplicates, preserving order(distinct [1 2 2 3])[1 2 3]
inbinaryMembership test (is element in vector?)(in 2 [1 2 3])true
exceptbinarySet difference (elements in A not in B)(except [1 2 3] [2])[1 3]
unionbinarySet union (deduplicated)(union [1 2] [2 3])[1 2 3]
sectbinarySet intersection(sect [1 2 3] [2 3 4])[2 3]
takebinaryTake first N elements (negative N takes from end)(take [10 20 30] 2)[10 20]
atbinaryIndex into vector (0-based)(at [10 20 30] 1)20
findbinaryFind index of first occurrence(find [10 20 30] 20)1
reverseunaryReverse element order(reverse [1 2 3])[3 2 1]
tilunaryGenerate range [0..n)(til 5)[0 1 2 3 4]
enlistvariadicWrap value(s) in a vector (list of atoms)(enlist 1 2 3)[1 2 3]
concatbinaryConcatenate two vectors or strings(concat [1 2] [3 4])[1 2 3 4]
razeunaryFlatten a list of vectors into one vector(raze (list [1 2] [3 4]))[1 2 3 4]
whereunaryIndices where boolean vector is true(where [true false true])[0 2]
groupunaryGroup indices by value (returns dict)(group ['a 'b 'a]) → dict
diverseunaryCheck if all elements are unique (no duplicates)(diverse [1 2 3])true
randbinaryGenerate N random values from range or sample from vector(rand 3 100) → 3 random ints 0..99
binbinaryBinary search — left boundary (sorted input)(bin [10 20 30] 25)1
binrbinaryBinary search — right boundary (sorted input)(binr [10 20 30] 25)2
; Build and manipulate vectors
(set v (til 10))             ; [0 1 2 3 4 5 6 7 8 9]
(take v 3)                  ; [0 1 2]
(take v -3)                 ; [7 8 9]
(at v (where (> v 5)))      ; [6 7 8 9]

; Set operations
(union [1 2 3] [3 4 5])   ; [1 2 3 4 5]
(sect [1 2 3] [2 3 4])    ; [2 3]
(except [1 2 3] [2])      ; [1 3]

Sorting & Ordering

Sort vectors, compute sort indices, and rank elements.

FunctionTypeFlagsDescriptionExample
ascunarySort ascending(asc [3 1 2])[1 2 3]
descunarySort descending(desc [3 1 2])[3 2 1]
iascunaryIndices that would sort ascending (grade up)(iasc [30 10 20])[1 2 0]
idescunaryIndices that would sort descending (grade down)(idesc [30 10 20])[0 2 1]
rankunaryRank of each element (0-based)(rank [30 10 20])[2 0 1]
xascbinarySort table ascending by column(s)(xasc 'price trades)
xdescbinarySort table descending by column(s)(xdesc 'price trades)
xrankbinaryAssign N rank buckets (quantile ranking)(xrank 4 [10 20 30 40])[0 1 2 3]
; Sort indices for reordering
(set v [30 10 20])
(at v (iasc v))              ; [10 20 30]  same as (asc v)

; Sort a table by price descending
(xdesc 'price trades)

; Quantile buckets
(xrank 10 (til 100))        ; 10 equal-sized buckets 0..9

Control Flow & Special Forms

Special forms receive their arguments unevaluated. These are the core language primitives for binding, branching, function definition, and error handling.

FunctionTypeFlagsDescriptionExample
setbinaryspecial, restrictedBind value to global variable(set x 42)
letbinaryspecialBind value to local variable (lexical scope)(let y (+ x 1))
ifvariadicspecialConditional: (if cond then else)(if (> x 0) "pos" "neg")
dovariadicspecialSequential execution, returns last value(do (set x 1) (set y 2) (+ x y))
fnvariadicspecialCreate lambda function(fn [x y] (+ x y))
trybinaryspecialError handling: (try expr handler-fn)(try (/ 1 0) (fn [e] 0))
raiseunaryThrow an error with message(raise "bad input")
returnunaryEarly return from function body(return 42)
quotevariadicspecialReturn argument unevaluated(quote (+ 1 2))(+ 1 2)
altervariadicspecialIn-place mutation of table column(alter trades 'price (* price 1.1))
delvariadicspecial, restrictedDelete columns or rows from table(del trades 'temp_col)
; Variable binding and branching
(set threshold 100)
(set classify (fn [x]
  (if (> x threshold) "high"
      (> x 50)        "mid"
                        "low")))

; Error handling
(try
  (/ 100 0)
  (fn [err] (println "caught:" err) 0))

Table Operations

Create and manipulate tables, dictionaries, and their metadata.

FunctionTypeFlagsDescriptionExample
listvariadicCreate a list from vectors (column data for tables)(list [1 2] ['a 'b])
tablebinaryCreate table from column names and list of vectors(table [x y] (list [1 2] ['a 'b]))
dictbinaryCreate dictionary from keys and values vectors(dict ['a 'b] [1 2])
keyunaryGet column names (table) or keys (dict)(key trades)[sym price size]
valueunaryGet column data (table) or values (dict)(value d)
getbinaryLookup key in dict or column in table(get d 'a)1
removebinaryRemove key from dictionary(remove d 'a)
rowbinaryExtract single row from table as dict(row trades 0)
metaunaryGet table metadata (column types, lengths)(meta trades)
union-allbinaryConcatenate two tables (all rows, no dedup)(union-all t1 t2)
unifybinaryMerge two tables/dicts (second takes precedence)(unify d1 d2)
modifyvariadicrestrictedFunctional table update (returns new table)(modify trades 'price (fn [p] (* p 1.1)))
pivotvariadicPivot table — reshape long to wide format(pivot trades 'sym 'date 'price)
; Create a table
(set trades (table [sym price size]
  (list ['AAPL 'GOOG 'AAPL]
        [150.0 2800.0 151.0]
        [100 50 200])))

; Dictionary operations
(set d (dict ['name 'age] ["Alice" 30]))
(get d 'name)              ; "Alice"
(key d)                      ; [name age]

; Pivot: long to wide
(pivot trades 'sym 'date 'price)

Query Operations

Special forms that bridge to the Rayforce DAG executor for high-performance columnar queries.

FunctionTypeFlagsDescriptionExample
selectvariadicspecialQuery table with optional filter, projection, grouping, and aggregation(select {from: t cols: {a: a}})
updatevariadicspecial, restrictedAdd or modify columns in a table (mutates in-place)(update {from: t cols: {b: (* a 2)}})
insertvariadicspecial, restrictedInsert rows into a table(insert t {x: 10 y: 20})
upsertvariadicspecial, restrictedInsert or update rows by key match(upsert t {x: 10 y: 20})
; Select with filter and projection
(select {from: trades
         where: (> price 100)
         cols: {sym: sym notional: (* price size)}})

; Group-by with VWAP
(select {from: trades
         by:   {sym: sym}
         cols: {vwap: (/ (sum (* price size)) (sum size))
                n: (count price)}})

; Update: add computed column
(update {from: trades
         cols: {notional: (* price size)}})

Joins

Rayforce supports six join types, including time-series-aware as-of and window joins.

FunctionTypeFlagsDescriptionExample
left-joinvariadicLeft join — all left rows, unmatched filled with null(left-join trades quotes 'sym)
inner-joinvariadicInner join — only matching rows from both sides(inner-join orders products 'product_id)
anti-joinvariadicAnti-semi-join — left rows with no right match(anti-join t1 t2 'key)
window-joinvariadicspecialWindow join — match rows within a time range(window-join {left: t1 right: t2 ...})
window-join1variadicspecialWindow join variant (single-row match per window)(window-join1 {left: t1 right: t2 ...})
asof-joinvariadicAs-of join — match most recent preceding value(asof-join trades quotes 'sym)
; Left join on sym column
(left-join trades quotes 'sym)

; Window join: match trades to quotes within 1-second window
(window-join {left: trades  right: quotes
              on: [sym]  window: [-1000 0]
              cols: {avg_bid: (avg bid)}})

; As-of join: find most recent quote for each trade
(asof-join trades quotes 'sym)

Pivot

FunctionTypeFlagsDescriptionExample
pivotvariadicPivot table — reshape long to wide. Args: table, row-key col, col-key col, value col(pivot sales 'region 'product 'revenue)
; Pivot sales data: rows=region, cols=product, values=revenue
(set sales (table [region product revenue]
  (list ['east 'east 'west 'west]
        ['widgets 'gadgets 'widgets 'gadgets]
        [100 200 150 250])))
(pivot sales 'region 'product 'revenue)

String Operations

String functions available as builtins. Additional string operations (UPPER, LOWER, TRIM, SUBSTR, REPLACE, STRLEN) are available at the DAG executor level via select/update.

FunctionTypeFlagsDescriptionExample
splitbinarySplit string by delimiter into vector of strings(split "a,b,c" ",")["a" "b" "c"]
likebinaryGlob-style pattern match (* and ? wildcards)(like "hello" "hel*")true
sym-nameunaryResolve integer sym IDs to symbols (passthrough for sym atoms)(sym-name 0) → sym at ID 0
; Split and rejoin
(split "2026-04-16" "-")    ; ["2026" "04" "16"]

; Pattern matching on a vector of strings
(like ["apple" "banana" "avocado"] "a*")
; [true false true]

; String concat also works on strings
(concat "hello" " world")  ; "hello world"

Date & Time

Temporal constructors. Pass 0 to get the current clock value. Cross-temporal comparisons are supported (dates, times, timestamps are all converted to nanoseconds internally).

FunctionTypeFlagsDescriptionExample
dateunaryCurrent date, or extract date from timestamp(date 0) → today's date
timeunaryCurrent time, or extract time from timestamp(time 0) → current time
timestampunaryCurrent timestamp (nanosecond precision)(timestamp 0)
; Get current date/time
(date 0)                    ; 2026.04.16
(time 0)                    ; 14:30:00.000000000
(timestamp 0)               ; 2026.04.16T14:30:00.000000000

Type & Introspection

Type checking, casting, null testing, and object inspection.

FunctionTypeFlagsDescriptionExample
typeunaryGet the type name of a value(type 42)'i64
asbinaryCast value to another type(as 'i64 "42")42
nil?unaryTest if value is null(nil? 0Ni)true
rcunaryGet reference count of an object(rc x)1
guidunaryGenerate N GUIDs (pass 0 for a single GUID)(guid 0)
; Type checking and casting
(type [1 2 3])              ; "I64"
(type "hello")              ; "str"
(as 'f64 [1 2 3])          ; [1.0 2.0 3.0]
(nil? 0Ni)                   ; true

; Generate a batch of GUIDs
(guid 5)                    ; vector of 5 GUIDs

I/O & Output

Printing, file I/O, CSV loading, and script execution.

FunctionTypeFlagsDescriptionExample
printlnvariadicPrint values with newline(println "hello" 42)
printunaryPrint value without newline(print "hello")
showvariadicPretty-print a value (tables formatted)(show trades)
formatvariadicFormat value to string (% as placeholder)(format "val=%" 42)"val=42"
.csv.readvariadicrestrictedLoad CSV file into table (mmap, parallel parse)(.csv.read "data.csv")
.csv.writevariadicrestrictedWrite table to CSV file(.csv.write trades "out.csv")
readunaryrestrictedRead file contents as string(read "file.txt")
writebinaryrestrictedWrite string to file(write "file.txt" "content")
loadunaryrestrictedLoad and evaluate a Rayfall script file(load "lib.rfl")
exitunaryrestrictedExit the process with status code(exit 0)
resolvevariadicspecialResolve a symbol in the current scope(resolve 'x)
timeitvariadicspecialBenchmark an expression (prints elapsed time)(timeit (sum (til 1000000)))
; Load and query CSV data
(set trades (.csv.read "trades.csv"))
(show trades)
(println (format "Loaded % rows" (count (value (first (value trades))))))

; Benchmark
(timeit (sum (til 10000000)))

System & Utility

System interaction, metaprogramming, diagnostics, and runtime inspection.

FunctionTypeFlagsDescriptionExample
evalunaryEvaluate a parsed Rayfall expression(eval (parse "(+ 1 2)"))3
parseunaryParse a string into a Rayfall expression tree(parse "(+ 1 2)")
.sys.gcvariadicTrigger GC / heap flush, returns 0(.sys.gc)
.sys.execunaryrestrictedExecute a shell command, return exit code(.sys.exec "ls -la")
.os.getenvunaryrestrictedGet environment variable value(.os.getenv "HOME")
.os.setenvbinaryrestrictedSet environment variable(.os.setenv "KEY" "value")
argsunaryGet command-line arguments as vector(args 0)
envunaryList all global environment bindings(env 0)
timerunaryHigh-resolution monotonic nanosecond clock(timer 0)
.sys.buildvariadicBuild metadata dict with version + build-date(.sys.build)
.sys.memvariadicMemory allocator statistics (alloc / peak / slab hits)(.sys.mem)
.sys.infovariadicSystem information (cores, page size, total memory)(.sys.info)
; Metaprogramming: parse and eval
(set expr (parse "(+ 10 20)"))
(eval expr)                  ; 30

; Timing with nanosecond clock
(set t0 (timer 0))
(sum (til 1000000))
(println (format "%ns" (- (timer 0) t0)))

; System diagnostics
(.sys.info 0)                  ; OS, CPU cores, memory budget
(.sys.mem 0)                  ; heap usage statistics

Serialization

Binary serialization for any Rayforce object. Useful for IPC, caching, and persistence.

FunctionTypeFlagsDescriptionExample
serunarySerialize any value to binary format (byte vector)(ser [1 2 3])
deunaryDeserialize from binary format back to value(de bytes)[1 2 3]
; Round-trip serialization
(set data [1 2 3])
(set bytes (ser data))
(de bytes)                   ; [1 2 3]

; Serialize a table for caching
(write "cache.bin" (ser trades))
(set cached (de (read "cache.bin")))

Storage

Persistent columnar storage — splayed (one file per column) and partitioned tables.

FunctionTypeFlagsDescriptionExample
.db.splayed.setvariadicrestrictedSave table as splayed columns to a directory(.db.splayed.set "db/trades" trades)
.db.splayed.getvariadicLoad splayed table from a directory(.db.splayed.get "db/trades")
.db.parted.getvariadicLoad partitioned table from root directory(.db.parted.get "db" 'trades)
; Save and reload a splayed table
(.db.splayed.set "db/trades" trades)
(set t (.db.splayed.get "db/trades"))
(show t)

; Load a date-partitioned table
(set hist (.db.parted.get "db" 'trades))

IPC (Inter-Process Communication)

TCP-based IPC for connecting to remote Rayforce instances. Uses binary serialization on the wire.

FunctionTypeFlagsDescriptionExample
.ipc.openunaryrestrictedOpen TCP connection to host:port, returns handle(.ipc.open "localhost:5000")
.ipc.closeunaryrestrictedClose an IPC connection handle(.ipc.close h)
.ipc.sendbinaryrestrictedSend a value over an IPC handle (sync request)(.ipc.send h "(sum (til 100))")
; Connect to a remote Rayforce instance
(set h (.ipc.open "localhost:5000"))
(set result (.ipc.send h "(select {from: trades where: (> price 100)})"))
(show result)
(.ipc.close h)

EAV Triple Store

Built-in Entity-Attribute-Value store. The EAV table has three columns: e (entity, i64), a (attribute, sym), v (value, i64). Foundation for the Datalog engine.

FunctionTypeFlagsDescriptionExample
datomsvariadicCreate an empty EAV table(datoms)
assert-factvariadicAppend a triple (e, a, v) to the EAV table(assert-fact db 1 'name 100)
retract-factvariadicRemove a triple from the EAV table(retract-fact db 1 'name 100)
scan-eavvariadicQuery EAV by attribute, returns (e, v) table(scan-eav db 'name)
pullvariadicEntity-centric retrieval — returns all attributes as dict(pull db 1){name:100 age:30}
; Build a knowledge base with EAV triples
(set db (datoms))
(set db (assert-fact db 1 'name 100))
(set db (assert-fact db 1 'age 30))
(set db (assert-fact db 2 'name 200))

(pull db 1)                  ; {name:100 age:30}
(scan-eav db 'name)         ; table of (e, v) where a=name

Datalog

Datalog rules and queries integrate with the EAV store. Rules use the (?entity :attribute ?value) pattern to match triples. Supports recursive rules and stratified negation.

FunctionTypeFlagsDescriptionExample
rulevariadicspecialDefine a Datalog rule (head + body clauses)(rule (path ?x ?y) (?x :edge ?y))
queryvariadicspecialCompile and execute a Datalog query against EAV store(query db (find ?x ?y) (where (path ?x ?y)))
; Recursive transitive closure
(rule (path ?x ?y) (?x :edge ?y))
(rule (path ?x ?z) (?x :edge ?y) (path ?y ?z))

(set db (datoms))
(set db (assert-fact db 1 'edge 2))
(set db (assert-fact db 2 'edge 3))
(query db (find ?x ?y) (where (path ?x ?y)))
; (1,2) (1,3) (2,3)

; Stratified negation: nodes with no outgoing edges
(rule (leaf ?x) (?x :edge ?_) (not (?x :edge ?_)))
(query db (find ?x) (where (leaf ?x)))

Datalog Program API

Low-level API for building and evaluating Datalog programs directly, bypassing the EAV store. Useful for custom base relations from tables.

FunctionTypeFlagsDescriptionExample
dl-programvariadicCreate an empty Datalog program(dl-program)
dl-add-edbvariadicRegister a base relation (table + arity)(dl-add-edb prog 'edge tbl 2)
dl-stratifyunaryCompute strata for the program (required before eval)(dl-stratify prog)
dl-evalunaryEvaluate program to fixpoint (semi-naive iteration)(dl-eval prog)
dl-querybinaryQuery a derived or base relation by name(dl-query prog 'path)
dl-provenancebinaryGet derivation provenance tracking for a relation(dl-provenance prog 'path)
; Build a Datalog program from a table
(set edges (table [x y] (list [1 2 3] [2 3 4])))
(set prog (dl-program))
(dl-add-edb prog 'edge edges 2)

; Add rules and evaluate
(rule (path ?x ?y) (edge ?x ?y))
(rule (path ?x ?z) (edge ?x ?y) (path ?y ?z))
(dl-stratify prog)
(dl-eval prog)

; Query results
(dl-query prog 'path)       ; all reachable pairs
(dl-provenance prog 'path)  ; derivation tracking