- Joined
- Jul 20, 2025
- Messages
- 126
- Thread Author
- #1
Introduction
MiniKanren is an embedded constraint logic programming language designed for writing programs as relations, rather than as functions or procedures. Unlike a function, a miniKanren relation makes no distinction between its inputs and outputs, leading to a variety of fascinating behaviors. For example, an interpreter written as a relation can also perform code synthesis, symbolic execution, and many other tasks. Core miniKanren has only 3 operators:
Representing Syntax
To move beyond simple scalars (like 5 or 6), we use recursive relations to define grammars. A Lambda Calculus term consists of three parts: Variables, Abstractions (Lambdas), and Applications.
Divergent Search
Because these are relations, we can use the same code for three distinct purposes by changing which parts of the call are "logic variables" (unknowns).
Type Inference and the Turnstile
($\Gamma \vdash e : \tau$) The "Vision" concludes by showing that an interpreter/type-checker written relationally can perform type synthesis.
References
Erlang Solutions, ed. 2015. /A Vision for Relational Programming in
miniKanren - William E. Byrd/. Directed by Erlang
Solutions. <>.
MiniKanren is an embedded constraint logic programming language designed for writing programs as relations, rather than as functions or procedures. Unlike a function, a miniKanren relation makes no distinction between its inputs and outputs, leading to a variety of fascinating behaviors. For example, an interpreter written as a relation can also perform code synthesis, symbolic execution, and many other tasks. Core miniKanren has only 3 operators:
- Unification: a two-way pattern matcher. It can be thought of as a type of equality operator. It matches variables on both sides.
This asserts that 5 is equal to 5, and will return `False' if it isnt. However, if a variable we dont know like `(== x 5)` is put in, x is also 5. This is an assertion. Just like the lisp I am building, each line is seperate. `(eq x 5) and (eq x 6)` is not inconsistent, because they are different branches.Code:[== 5 5]
- `fresh': fresh introduces scoped logic variables; goals inside a fresh form are implicitly conjoined.
- `conde': Disjunction. This is similar to lisps `cond' operator. It allows us to get multiple answers. We can see the result of each clause independently. Each clause represents an alternative logical branch; results are interleaved fairly during search.
Will give `True', and `True'. Although the information appears inconsistent.Code:(fresh (y) (conde ((== x 5)) ((== x 6)) )
Representing Syntax
To move beyond simple scalars (like 5 or 6), we use recursive relations to define grammars. A Lambda Calculus term consists of three parts: Variables, Abstractions (Lambdas), and Applications.
Code:
x #variable. . We use the symbolo constraint to ensure a logic variable represents a scheme symbol.
\lambda x. y #abstraction
(f arg) # application
Divergent Search
Because these are relations, we can use the same code for three distinct purposes by changing which parts of the call are "logic variables" (unknowns).
- `(LC-syn '(lambda (x) x))' Returns Success.
- `(LC-syn q)' Returns an infinite stream of all possible valid Lambda Calculus terms.
- `(LC-syn '(lambda (x) ,q))' and this fills the hole with valid bodies.
Type Inference and the Turnstile
($\Gamma \vdash e : \tau$) The "Vision" concludes by showing that an interpreter/type-checker written relationally can perform type synthesis.
- Environment ($\Gamma$): A mapping of variables to types.
- Expression ($e$): The program code.
- Type ($\tau$): The resulting type (e.g., Int, Bool, or a function type).
References
Erlang Solutions, ed. 2015. /A Vision for Relational Programming in
miniKanren - William E. Byrd/. Directed by Erlang
Solutions. <>.