Skip to content

Bracket Depth Hierarchy

Understanding LOVE-LANG's five-level bracket system and what each level means.

The most distinctive feature of LOVE-LANG is its bracket depth hierarchy — a topological encoding where the number of brackets indicates the semantic ring (level) of an expression.

This is not a quirky syntactic choice. It is a load-bearing architectural invariant that makes the LOVE evaluator’s behaviour provably composable.


┌─────────────────────────────────────────────────────────────────┐
│ [[[[[ L5 — System FFI / I/O / Side-Effects ]]]]] │
│ [[[[ L4 — Compiler Directives / Macros ]]]] │
│ [[[ L3 — Type Contracts / Structural Schemas ]]] │
│ [[ L2 — Pure Operations / Standard Library Math ]] │
│ [ L1 — Variables / Primitive References ] │
└─────────────────────────────────────────────────────────────────┘

Each outer ring encompasses all inner rings. L5 can call L4, which can call L3, and so on. But an inner ring cannot escape to an outer ring without crossing a trust boundary.


“Just data.”

The simplest form. Single brackets wrap a list of atoms and other expressions.

# Primitive list
colours = [red green blue]
# Nested references
pair = [first-name last-name]
# Mixed atoms
meta = ["LOVE" :version 1 true]

When to use: Any time you are grouping values, building a list, or referencing other variables.


“Pure computation. No surprises.”

Double brackets invoke a pure function from the standard library. These expressions always produce the same output for the same input. No I/O, no state mutation.

sum = [[ + 1 2 3 ]]
product = [[ * 6 7 ]]
greeted = [[ String.concat "Hello, " name ]]
validated = [[ List.contains allowed-roles :admin ]]

When to use: Mathematical operations, string manipulation, list processing.


“Proofs about shape.”

Triple brackets define structural schemas — compile-time type checks that validate the shape of data flowing through your programme.

# Define a type contract
UserPayload = [[[
name @[String]
email @[String]
age @[Number]
roles @[List]
]]]
# Use it as a validator
validated-user = [[[ UserPayload ]]] raw-input

When to use: Defining data shapes, validating inputs at API boundaries, and describing record structures.


“Talking to the compiler.”

Quadruple brackets issue compile-time instructions to the LOVE evaluator itself. These control optimization, code generation mode, and inlining behaviour.

build-config = [[[[
#mode Production
#target wasm
#inline true
#strict type-checking
]]]]
# Using a macro
expanded = [[[[
@macro[repeat 5] [print "hello"]
]]]]

When to use: Setting build modes, defining macros, compiler hints.


“Where programmes meet the world.”

Five brackets are the most powerful and most dangerous ring. They cross the boundary from pure computation into the real world: databases, networks, files, screen output.

# Write to a database
[[[[[
@sql_write "users" [[[ UserPayload ]]] { :name user-name :hash hashed-pass }
]]]]]
# HTTP request
[[[[[
@http_post endpoint-url payload
]]]]]
# Display to user
[[[[[
@print "Programme complete."
]]]]]

When to use: Any side-effecting operation. These must be declared as effectors in model.edn.


Levels compose naturally. Inner expressions resolve first:

# L2 wrapping an L1
result = [[ + [1 2 3] 10 ]]
# L5 wrapping L3 wrapping L1
[[[[[
@sql_write "records"
[[[ RecordSchema ]]] {
:id [generate-uuid]
:data payload
}
]]]]]

BracketsLevelNameSide-Effects?Compile-Time?
[ ]L1Data
[[ ]]L2Operations
[[[ ]]]L3Contracts✓ (type phase)
[[[[ ]]]]L4Directives
[[[[[ ]]]]]L5System FFI