Reputation: 539
I am working in prolog and bumped into something I haven't really managed to grasp. To work without variables and with constant symbols and functions, for example:
test(a,T) :- /* change constant a, put result in T */
test(b,T) :- /* change constant b, put result in T */
test(f(X,Y),T) :- /* change function f and possibly the terms X and Y */
Is this doable? I don't really understand these non-variables way of putitng it and would be glad if someone could provide an insight, thanks in advance!
Upvotes: 1
Views: 901
Reputation:
To add to the answer by @mat:
You don't really have constants vs. variables, as in traditional imperative languages. You have terms, and terms can be, as far as their binding is concerned:
Few examples from the top-level:
?- X = Y.
X = Y.
Both X and Y are now the same unbound variable term.
?- 3 = X.
X = 3.
X is bound to the value of 3.
?- X = foo(a, b).
X = foo(a, b).
X is bound to the compound term foo(a, b)
. X is now "ground":
?- X = foo(a, b), ground(X).
X = foo(a, b).
?- X = foo(Y, b).
X = foo(Y, b).
X is bound to the partial term foo(Y, b)
. Y here is an unbound variable. If you ask whether X is ground, the query fails:
?- X = foo(Y, b), ground(X).
false.
A predicate can describe a relationship between terms. For example, the built-in predicate plus/3
describes the following relationship:
?- plus(1, 2, 3).
true.
?- plus(1, 2, X).
X = 3.
?- plus(X, 2, 4).
X = 2.
Now to the last example that you have given: in test(f(X,Y), T)
, f(X,Y)
is not a function: it is a compound term with arity 2, so, f/2
. You can evaluate it, as if it were a predicate, or change it in some way to get a different term in the second argument. For example, to switch the argument order:
switch(f(X, Y), f(Y, X)).
With this, you could pose queries like:
?- switch(f(1,2), T).
T = f(2, 1).
?- switch(T, f(a,b)).
T = f(b, a).
?- switch(f(1,X), T), X = foo(bar, baz).
X = foo(bar, baz),
T = f(foo(bar, baz), 1).
So if you wanted a very artificial predicate foo(X, Y)
that is defined as follows:
a
and Y is aa
, orb
and Y is bbb
, orf/2
, and Y is the compound term g/2
in which the order of the arguments of f/2
is switched.Implementation:
foo(a, aa).
foo(b, bbb).
foo(f(A, B), g(B, A)).
Terms that are partially bound, also called partial data structures, with "holes" in them, are useful in many different ways. One naive way of implementing a first in, first out queue could be:
% empty_queue(Q) creates an emtpy queue
empty_queue(q(Q,Q)).
% enqueue(Q0, X, Q) enqueues X to the queue Q0, resulting in Q
enqueue(q(Front, [X|Back]), X, q(Front, Back)).
% dequeue(Q0, X, Q) dequeues X from the queue Q0, resulting in Q
dequeue(q([X|Front], Back), X, q(Front, Back)).
You can see for yourself how works and how you can break it (try dequeuing elements you have not enqueued yet!). There are better ways to make a queue, but this is just to show how you can use a partial data structure. If you only use the queue term through these three predicates (empty_queue/1
, enqueue/3
, dequeue/3
), the "back" will always be a free variable.
You need to ask a more specific question for a more specific answer than this.
Upvotes: 3
Reputation: 40768
You must think in terms of relations between different variables.
So, if you want to define a transition between an old value and a new value, you need an additional argument:
state0_state(OldState, NewState) :- NewState = <define yourself> .
The advantage of such relations is that they can often be used in all directions: You can use them to ask, for example: Which old states yield a specific new state? Or more generally: Which transitions are possible at all?
Upvotes: 2