Administrative Normal Form (ANF) in AILANG
Why ANF?
ANF makes evaluation and lowering explicit and predictable: every non-trivial expression is bound to a name before it's used. This gives us simple sequencing, easy instrumentation, and type-guided lowering with no guesswork.
TL;DR
- Complex sub-expressions are lifted into let bindings.
- Operator applications become intrinsics with explicit args.
- ANF is the only form seen by the typechecker and lowerer.
- Pair ANF with CoreTypeInfo for type-guided operator selection.
From Surface → ANF (Core)
Surface:
let z = ([1,2] ++ [3,4]) in z
Core (ANF), conceptual:
Let $t1 = List(1,2)
Let $t2 = List(3,4)
Let $t3 = Intrinsic(OpConcat, [$t1, $t2])
In Var($t3)
Reading ANF
- Let:
Let name = value in body. - Intrinsic: a primitive operation (
OpConcat,OpAdd, …). - Var: usage site of a previously bound value.
- NodeID: stable integer identity; keys into CoreTypeInfo.
Type Information: CoreTypeInfo
- Produced during Core type inference.
- Map:
NodeID -> types.Type. - Threaded into the lowering pass; authoritative for decisions.
Use CoreTypeInfo first. Fall back to ANF shape only when types are unavailable (e.g., synthetic nodes created after inference).
Common Patterns
Binding chains
Let a = Var b
Let b = Var c
Let c = List(1)
Use core.ResolveValue(expr, binds) to chase once; it cycle-detects.
Polymorphic operators
Lowering chooses builtin by type head (String/List/Int/etc.), not by shape.
Debugging ANF & Types
$ ailang debug ast myfile.ail --show-types
=== Core AST (ANF) ===
...
[#11] Intrinsic(OpConcat)
Arg[0]: Var(xs) :: List[int]
Arg[1]: Var(ys) :: List[int]
Result :: List[int]
Gotchas
- ANF means intrinsic args are usually Vars. Resolve via bindings if you must inspect shapes.
- Keep AST nodes alive through lowering; CoreTypeInfo keys by NodeID.
- If runtime says "wrong builtin selected", verify CoreTypeInfo reached the lowerer.
See Also
- Adding Operators Guide - Step-by-step operator implementation
internal/core/helpers.go- ANF traversal utilitiesinternal/types/typeinfo.go- CoreTypeInfo implementationcmd/ailang/debug.go- Debug CLI implementation