← MeTTa Tutorial · Lesson 2 of 5
Patterns of Knowledge. MeTTa keeps knowledge as atoms in a Space and retrieves it by matching patterns. This lesson covers querying a Space, the unification that powers both queries and function calls, and nesting queries inside one another.
The Space you work in is called &self. Add facts just by writing them; retrieve them with match, which takes a Space, a pattern, and a template to return for each match:
; facts in the current Space
(parent Tom Bob)
(parent Bob Ann)
(parent Pam Bob)
; who are Bob's parents? pattern (parent $x Bob) -> return $x
!(match &self (parent $x Bob) $x) ; [Tom, Pam]
A variable such as $x in the pattern matches any atom, and match yields the template once per matching atom — so a query naturally returns multiple results (the nondeterminism from Lesson 1).
The engine behind matching is unification: making two atoms identical by binding variables. It is the same machinery that evaluates functions — calling (double 21) unifies it with the rule (= (double $x) ...), binding $x to 21. You can invoke it directly with unify, which returns its third argument on a match and its fourth on a miss:
!(unify (parent Tom $who) (parent Tom Bob) $who not-found) ; [Bob]
!(unify (parent Tom $who) (cat Felix) $who not-found) ; [not-found]
Because rules are patterns, a function can query the Space as part of its definition:
(= (parents-of $child) (match &self (parent $p $child) $p))
!(parents-of Bob) ; [Tom, Pam]
A template can itself contain a match, letting you chain relationships. Here a grandchild is “the child of a child”:
(= (grandchildren-of $x)
(match &self (parent $x $child)
(match &self (parent $child $gc) $gc)))
!(grandchildren-of Tom) ; [Ann]
The outer query binds $child to Bob; the inner query then finds Bob's children. Nesting queries this way is how MeTTa expresses multi-step reasoning over a knowledge graph.
Lesson 3 — Types and Metatypes: giving atoms types, parametric types, and using types to control evaluation.