Macros and Meta¶
Makrell# is building a substantial compile-time system in the .NET ecosystem. This page explains the current shape of that system at a user level: what the main forms are, what they are for, and how they relate to the rest of the Makrell family.
Important themes¶
The current Makrell# compile-time model revolves around:
quoteandunquotecompile-time
metaexecutionMakrell-defined macros
replayable compile-time metadata via
importmwhitespace-preserving macro input when needed
pattern matching inside compile-time code
Representative macro example¶
{meta
greeting = {quote "Hello from meta"}}
{def macro hello [ns]
{quote {String.Join " " [{unquote greeting} "and macros"]}}}
This example shows the basic split:
metadefines compile-time valuesdef macrotransforms syntaxquoteandunquotecontrol what is treated as syntax and what is evaluated during expansion
Current model¶
Makrell# already supports a meaningful compile-time model built around:
quoteandunquotetop-level
metaexecutionMakrell-defined macros
replayable compile-time metadata for
importm-style workflows
That means the .NET track is not only compiling ordinary runtime expressions. It is also carrying a genuine compile-time layer that participates in the compile and dynamic-load workflow.
How to think about meta¶
Use meta when you want compile-time definitions or helper logic that should
run during compilation rather than at runtime. In practice, that often means:
preparing quoted syntax
defining compile-time helper values
sharing compile-time state across macro definitions
using
matchor~=to dispatch on syntax and small compile-time values
The important distinction is that meta is not ordinary runtime code placed
early in the file. It belongs to the compile-time phase.
Compile-time pattern matching¶
Makrell# meta now reuses the same basic pattern engine as runtime Makrell# for common compile-time cases. In practice, that means compile-time code can use:
match~=!~=capture bindings such as
name=_guarded clauses written with
{when ...}
That makes syntax-directed macros cleaner, because a macro can often dispatch on its input with Makrell-shaped matching logic instead of open-coded indexing and manual checks.
{def macro second [ns]
ns = {regular ns}
{match ns
[_ value=_ $rest]
{quote {unquote value}}
_
{quote null}}}
{second 2 3 5}
How to think about macros¶
Macros in Makrell# receive syntax and produce syntax. A practical way to work with them is:
keep them structurally explicit
return quoted syntax rather than hiding too much work behind one form
keep compile-time logic in
metahelpers when that makes the macro itself easier to read
Small macros are usually easier to inspect and debug than large, multi-responsibility macros.
Why whitespace preservation matters¶
One practical requirement in the Makrell family is that some macro consumers need access to original source-shaped nodes, including whitespace-sensitive structure.
That matters for:
embedded sublanguages
MRML-like forms
macros that must decide for themselves whether to regularise input
So the macro system is not only a convenience feature. It is part of how Makrell# supports language extension in a structured way.
importm and replayable metadata¶
Makrell# can embed replayable compile-time sources in built assemblies. That is
what later enables importm-style workflows: compile-time definitions can be
reloaded and replayed in another compilation step.
At a practical level, this means the .NET implementation treats compile-time behaviour as part of the module story, not as an entirely separate external tooling step.
How to approach this section¶
If you are new to Makrell# macros and meta:
read this page for the overall model
use Macro and Meta Recipes for smaller practical patterns
use the CLI workflow pages when you want to inspect emitted code or embedded compile-time metadata