Recursion and control
MeTTa has no loops. Repetition is recursion, just as in other functional languages, and it pairs naturally with recursive data.
Recursion over a list
A common list encoding is a cons list: the empty list is (), and a cons cell is (:: head tail). So [A, B, C] is (:: A (:: B (:: C ()))). Counting its elements is two rules, a base case and a recursive case:
The two rules are mutually exclusive in practice, so together they act like a conditional. Notice we never declared a list type; :: and () are just atoms we chose. length works on this shape and is simply left unreduced on anything else.
Higher-order functions
A rule can take another function as an argument, because to MeTTa it is all just atoms to assemble into an expression:
That makes map over a cons list straightforward:
Conditionals with if
Grounded numbers cannot be taken apart by pattern matching, so for arithmetic recursion you reach for if, which works like if-then-else anywhere:
Crucially, if does not evaluate both branches; only the taken one runs. That is what stops factorial from recursing forever, and it is easy to see here:
Pattern matching with case
case matches an atom against a sequence of patterns, in order and mutually exclusively:
Where if checks a boolean condition, case matches structure. That makes it handy when several shapes need different handling, for example zipping two lists and treating "both empty", "both non-empty", and "anything else" as distinct cases:
Both if and case are ordinary MeTTa functions, not magic syntax. Next we look at what happens when patterns and nondeterminism meet: Free variables and nondeterminism.