4.6 KiB
This is one of Quarkdown’s most interesting ideas. It is not just “Markdown plus directives”; it is closer to a small document programming language embedded in Markdown.
Core Idea
In Quarkdown, function calls are the central extension mechanism. They use a dot-prefixed syntax:
.sum {26} {16}
Arguments can be positional or named:
.multiply {6} by:{3}
They can be inline, block-level, nested, chained, or given an indented body argument. Quarkdown explicitly presents functions as its key feature and groups them across layout, utility views, math/logical operations, control flow, file data, and document metadata. Source: Quarkdown function-call syntax.
What Makes It Rich
- Functions produce document content, not just scalar values
A function may return text, Markdown content, layout structures, booleans, numbers, tables, etc. This is crucial: document generation and computation live in the same language.
.if {.isadult age:{20}}
You're an adult!
User-defined functions are declared with .function, and their body is a lambda-like block:
.function {greet}
to from:
**Hello, .to** from .from!
Source: Declaring functions.
- Block arguments make functions feel Markdown-native
Instead of forcing everything into parenthesized expressions, Quarkdown lets the final argument be an indented block:
.box {Example}
This is the content of the example.
That is a very elegant move. It keeps prose readable while making structured composition possible.
- Chaining gives it pipeline ergonomics
This:
.pow {3} {2}::subtract {1}::sum {2}
is transformed conceptually into nested calls where each result becomes the first argument of the next call. That gives Quarkdown a pleasant Unix-pipe / method-chain feel without turning the surface language into JavaScript. Source: Chaining calls.
- Variables are functions too
Variables are defined with .var, then accessed like zero-argument functions:
.var {name} {Quarkdown}
Hello, .name!
They can hold simple values or block/layout content. There is also .let for scoped temporary variables. Sources: Variables and Let.
- It has real control flow
Quarkdown has conditional functions like .if and .ifnot, plus loops like .foreach and .repeat:
.foreach {1..3}
n:
The number is **.n**
The loop returns an iterable of evaluated results, so it behaves more like map than a pure side-effect loop. Source: Loops.
- It has higher-order behavior
Lambdas show up in custom functions, let, foreach, sorting, filtering, and table operations. Inline lambdas can be passed as arguments, for example in table filtering:
.tablefilter {2} {@lambda x: .x::isgreater {20}}
...
Source: Table manipulation.
- It includes typed-ish document values
The docs list value types such as string, number, Markdown content, boolean, none, iterable, dictionary, range, lambda, size, color, and dynamic values. It is weak/dynamic enough to remain author-friendly, but structured enough to support meaningful diagnostics and reusable functions.
Why This Matters For Markitect
For Markitect, the lesson is not necessarily “copy Quarkdown syntax.” The deeper lesson is this:
Quarkdown treats document operations as composable functions with Markdown-native block bodies.
That maps beautifully to our direction:
- Markitect contracts could define allowed/expected processors as named document functions.
- Our fenced-block processors could grow into a function registry with capability metadata.
- Our dataflow pipelines could benefit from function chaining semantics.
- Our template/generation layer could distinguish pure deterministic functions, context-bound functions, LLM-backed functions, and unsafe external functions.
- Our diagnostics could be stronger than Quarkdown’s if every function call has provenance, declared inputs, permissions, and expected output type.
My take: Quarkdown’s function language is a very good inspiration for a future Markitect “document function layer,” especially if we keep it optional, markdown-close, typed enough for contracts, and integrated with our provenance/cache/access-control fabric.