# Quarkdown: Markdown That Computes — Functions, Variables, Scripting

> Part 2 of the Quarkdown series: function calls, chaining with ::, variables, custom functions, conditionals and loops. How Markdown becomes a genuine little programming language.

Source: https://www.jpkc.com/db/en/blog/quarkdown-funktionen-skripting/

In [part 1](https://www.jpkc.com/db/en/blog/quarkdown-einstieg/) I introduced Quarkdown as a Markdown superset with a single big idea: the function call. It sounded harmless — a dot, a few curly braces. But behind it lies what separates Quarkdown from every other Markdown dialect: **real scripting**. Variables, custom functions, conditionals, loops, mathematics — all directly in the document, all in Markdown notation. This is exactly what the "Turing-complete" promise means. In this part I get to the bottom of the mechanics.

## The anatomy of a function call

A call starts with a dot; arguments go in curly braces. Arguments can be **positional** (their meaning follows from their order) or **named** (`name:{value}`) — the latter makes the call more readable:

```markdown
.multiply {6} by:{3}
```

Calls can be **nested** by using one as the argument of another:

```markdown
.multiply {.pow {3} to:{2}} by:{.pi}
```

That doesn't stay readable for long. Which is why Quarkdown has its most elegant detail — **chaining** with `::`. The value on the left becomes the *first* argument of the function on the right. The barely readable

```markdown
.sum {.subtract {.pow {3} {2}} {1}} {2}
```

turns into the line you actually read like mathematics:

```markdown
.pow {3} {2}::subtract {1}::sum {2}
```

The rule behind it is simple: `.a::b` becomes `.b {.a}`, `.a::b::c` becomes `.c {.b {.a}}`. You can append further arguments at any time — the chained value always stays the first one.

A second important concept is the **block or body argument**: the indented content under a call, corresponding to the last parameter. It can span multiple lines and itself contain functions:

```markdown
.row alignment:{center}
    This document was made by .docauthor

    .column
        Its name is .docname
```

Important: the entire body shares the same indentation (at least two spaces or one tab). Indent one line by four spaces and you accidentally create a code block — one of the few pitfalls.

## Variables

You define a variable with `.var {name} {value}` and access it like a parameter-less function:

```markdown
.var {name} {Quarkdown}

Hello, **.name**!
```

Reassigning works at any point — including based on the old value:

```markdown
.var {number} {5}
.number {.number::sum {1}}
```

Variables aren't limited to simple values. Because a body argument may be multi-line, a variable can store a whole layout block and reuse it as often as you like:

```markdown
.var {myrow}
    .row gap:{2cm}
        A

        B

        C

.container background:{teal} padding:{1cm}
    .myrow
```

## Custom functions

The real tool against repetition is `.function`. It takes a name and a body; the parameters go as `param1 param2:` in the first body line:

```markdown
.function {greet}
    to from:
    Hello, .to from .from!

.greet {world} from:{John}
```

Three properties are worth remembering:

- **Optional parameters.** A `?` on the parameter name makes it optional; when the argument is missing, its value is [`None`](https://quarkdown.com/wiki/none). With `::otherwise {…}` you emulate a default:

  ```markdown
  .function {greet}
      to from?:
      Hello, .to from .from::otherwise {unnamed}!
  ```

- **No `return`.** Quarkdown has no return statement — *every* reached instruction becomes part of the output. A function can return any Markdown content or, because the language is weakly typed, any value type:

  ```markdown
  .function {area}
      width height:
      .multiply {.width} by:{.height}

  The area is **.area {4} {2}**.
  ```

- **Overwriting.** A function can be redeclared at any time; from then on the new definition applies. To prevent that, compile with `--forbid-function-overwriting` and get an error on name collisions.

## Conditionals

`.if` evaluates a boolean condition and outputs its body only then. The function *propagates* its content upward — so you can place it inside any expression, for instance to conditionally weave content into a layout:

```markdown
.row gap:{1cm}
    A

    .if {.iseven {3}}
        B

    C
```

There's no `else` (yet) — but with `.ifnot` and `.let` you can rebuild it cleanly:

```markdown
.let {.iseven {3}}
    condition:
    .if {.condition}
        3 is even!
    .ifnot {.condition}
        3 is odd!
```

## Loops

`.foreach` iterates over any iterable value — a number range, a Markdown list, a variable. The trick: the function behaves like a `map` and returns a collection of the same size, so you can use it as an expression. `.1` implicitly references the current item:

```markdown
.row alignment:{spacearound}
    .foreach {1..5}
        n:
        .multiply {.n} by:{.n}
```

`.repeat {n}` is shorthand for `.foreach {1..n}`.

## Mathematics, made readable

By the time you reach mathematics, chaining pays off. The area of a circle:

```markdown
.var {radius} {8}

The area is
.pow {.radius} to:{2}::multiply {.pi}::truncate {2}.
```

The same calculation nested would be a tangle of brackets — chained, it reads left to right like a natural formula. The full list of math functions is in the [standard library](https://quarkdown.com/docs/).

## FAQ

### Isn't that too much programming for a document?

You decide how far you go. For a simple text you need none of it. Scripting only pays off where repetition or dynamics come into play — the same box twenty times, a generated table, a calculation inside running text. Then one function replaces the copy-paste.

### Why `::` instead of nested braces?

Both are allowed and equivalent — `.a::b` is exactly `.b {.a}`. Chaining exists purely for readability: it flips the reading direction from "inside out" to "left to right," the way you think of calculation steps anyway.

### Are there data types?

Yes, but weakly typed: text, numbers, booleans, lists, dictionaries, ranges, colors, sizes and more. Values are converted as needed, and the type of iterated elements is preserved. I'll devote a dedicated section of the series to types later.

## Further reading

The introduction and positioning are in [part 1: When Markdown Learns Typesetting](https://www.jpkc.com/db/en/blog/quarkdown-einstieg/). In the next part I leave the logic layer and move to the visible result: **document types, themes and layout** — how the same source becomes a web page, paper, book or presentation. The full function reference is always in the [official wiki](https://quarkdown.com/wiki) and the [standard library](https://quarkdown.com/docs/).

