Ckini.Macro (Ckini v0.1.0) View Source
A set of MiniKanren-like primitives.
Link to this section Summary
Functions
Create a goal from a sequence of goals. The goal only succeeds when all the subgoals succeed.
Performs what's called a "soft-cut" operation in
Prolog. In each of its subgoals, if they are composed of multiple
goals and the first goal succeeds. conda/1 will behave like the subgoal
is the only branch.
Creates a goal from a sequence of subgoals by taking disjunction on them. In other words, this syntax creates multiple possibilities.
Creates a goal from a sequence of subgoals by taking disjunction on them. In other words, this syntax creates multiple possibilities.
Fresh introduces new logic variables into the block scoped by do..end. You can put the variables in a tuple to introduce many variables at the same time.
See documentation for matche/2.
The match{e,i,a,u} series syntax are equivalent to their cond{e,i,a,u} counterpart. They are handy to write pattern matching with a value (or another pattern) against multiple patterns.
See documentation for matche/2.
See documentation for matche/2.
Query for all possible values of a variable with a goal.
Query for a number of possible values of a variable with a goal.
Link to this section Functions
Create a goal from a sequence of goals. The goal only succeeds when all the subgoals succeed.
all/1 is functionally equivalent to fresh/1 except that it doesn't
introduce variables.
Examples
iex> use Ckini
iex> run(x) do
...> eq(x, 1)
...> all do
...> eq(x, 2)
...> eq(x, 1)
...> end
...> end
[]The preceding example is only for demonstration. The usage of
all/1 in the example is not necessary.
Performs what's called a "soft-cut" operation in
Prolog. In each of its subgoals, if they are composed of multiple
goals and the first goal succeeds. conda/1 will behave like the subgoal
is the only branch.
The syntax is the same as conde/1. See conde/1 for usage.
Examples
iex> use Ckini
iex> teacupo = fn x ->
...> conde do
...> _ -> eq(x, :tea)
...> _ -> eq(x, :cup)
...> end
...> end
iex> run({x, y}) do
...> conda do
...> _ ->
...> teacupo.(x)
...> eq(y, x)
...> _ ->
...> eq(x, 1)
...> eq(y, x)
...> end
...> end
[{:tea, :tea}, {:cup, :cup}]
iex> use Ckini
iex> teacupo = fn x ->
...> conde do
...> _ -> eq(x, :tea)
...> _ -> eq(x, :cup)
...> end
...> end
iex> run({x, y}) do
...> conda do
...> _ ->
...> teacupo.(x)
...> eq(1, 2)
...> _ ->
...> eq(x, 1)
...> eq(y, x)
...> end
...> end
[]
Creates a goal from a sequence of subgoals by taking disjunction on them. In other words, this syntax creates multiple possibilities.
conde performs depth-first search. Which means, conde will explore
all possibilities of the first subgoal before exploring the second
subgoal, and so on.
Each subgoal is represented by a -> expression in the do block.
The left-hand side of -> can be used to introduce new
variables. You can put a single variable, or multiple variables
enclosed by {}, or if no new variable is needed, put an _.
The right-hand side of -> can a single goal or multiple goals. If
multiple goals are supplied, they will be treated as if they are
enclosed in a all/1 goal.
Examples
iex> use Ckini
iex> run(x) do
...> conde do
...> _ -> eq(x, 2)
...> _ -> eq(x, 1)
...> end
...> end
[2, 1]
Creates a goal from a sequence of subgoals by taking disjunction on them. In other words, this syntax creates multiple possibilities.
Unlike conde/1, condi/1 performs a different type of search
that's different from depth-first search. It will explore both
breadth and depth in a zig-zag order, making it more useful for
many cases.
The syntax is the same as conde/1. See conde/1 for usage.
Examples
iex> use Ckini
iex> run(x) do
...> condi do
...> _ -> eq(x, 2)
...> _ -> eq(x, 1)
...> end
...> end
[2, 1]
Similar to conda/1 in the sense that it also treats
the first successful subgoal as the only branch. Unlike conda/1,
condu/1 also restrict its subgoal to have only one possibilities.
Examples
iex> use Ckini
iex> teacupo = fn x ->
...> conde do
...> _ -> eq(x, :tea)
...> _ -> eq(x, :cup)
...> end
...> end
iex> run({x, y}) do
...> condu do
...> _ ->
...> teacupo.(x)
...> eq(y, x)
...> _ ->
...> eq(x, 1)
...> eq(y, x)
...> end
...> end
[{:tea, :tea}]
iex> use Ckini
iex> teacupo = fn x ->
...> conde do
...> _ -> eq(x, :tea)
...> _ -> eq(x, :cup)
...> end
...> end
iex> run({x, y}) do
...> condu do
...> _ ->
...> teacupo.(x)
...> eq(1, 2)
...> _ ->
...> eq(x, 1)
...> eq(y, x)
...> end
...> end
[]
Fresh introduces new logic variables into the block scoped by do..end. You can put the variables in a tuple to introduce many variables at the same time.
Please note: with Ckini, you can minimize usage of fresh if you
intend to use it immediately in a cond and match clause, as cond
and match support introducing free variables via the left-hand-side
of ->.
See condi/1 and matchi/2 for details.
Examples
iex> use Ckini
iex> run q do
...> fresh x do
...> eq([x, q], [q, 1])
...> end
...> end
[1]
iex> run q do
...> fresh {x, y} do
...> eq([x, y, q], [y, 1, x])
...> end
...> end
[1]Also see all/1.
See documentation for matche/2.
The match{e,i,a,u} series syntax are equivalent to their cond{e,i,a,u} counterpart. They are handy to write pattern matching with a value (or another pattern) against multiple patterns.
The pattern can be a variable, a list, or a ground term. The
do...end block contains a series of clauses of pattern -> goals
syntax.
You can write logic variables freely in the pattern, as the will be
bind to corresponding value automatically. You can also use _ in
the pattern as a placeholder to ignore values you don't need.
If you need extra variables in the body other than those appeared in
pattern, you can use pattern, extra_variables -> goals
syntax. You can use {} to enclose multiple variables in
extra_variables as in fresh/1.
The implementation detail is that each match clause will be
converted to a cond clause by inserting a eq(value, pattern) goal
in front of other goals. The implication is that for matcha and
matchu, this eq goal will be treated as the conditional for the
rest of subgoals.
Examples
iex> use Ckini
iex> run(x) do
...> matche x do
...> _ -> succ()
...> [y, _] -> eq(y, 1)
...> [_, y] -> eq(y, 2)
...> [_, _] -> succ()
...> end
...> end
[:_0, [1, :_0], [:_0, 2], [:_0, :_1]]
iex> use Ckini
iex> run(x) do
...> matche x do
...> _ ->
...> succ()
...> [y, _], z ->
...> eq(y, z)
...> eq(z, 1)
...> [_, y], {z, w} ->
...> eq(y, [z, w])
...> [_, _] ->
...> succ()
...> end
...> end
[:_0, [1, :_0], [:_0, [:_1, :_2]], [:_0, :_1]]
See documentation for matche/2.
See documentation for matche/2.
Query for all possible values of a variable with a goal.
You can also query multiple variables by putting them in a tuple. The variable will be declared automatically.
You can also provide multiple goals by putting them in the do block.
Examples
iex> use Ckini
iex> run q do
...> end
[:_0]
iex> run {x, y} do
...> eq(x, 1)
...> conde do
...> _ -> eq(y, 1)
...> _ -> eq(y, 2)
...> _ -> eq(x, 2)
...> end
...> end
[{1, 1}, {1, 2}]Also see run/3 for limited of possible values.
Query for a number of possible values of a variable with a goal.
You can also query multiple variables by putting them in a tuple. The variable will be declared automatically.
You can also provide multiple goals by putting them in the do block.
Examples
iex> use Ckini
iex> run(2, q) do
...> conde do
...> _ -> eq(q, 1)
...> _ -> eq(q, 2)
...> _ -> eq(q, 3)
...> _ -> eq(q, 4)
...> end
...> end
[1, 2]Also see run/2 that allows querying unlimited possible values.