I'm trying to learn prolog now and I started recursion topic. Came across this example for successor.
numeral(0).
numeral(succ(X)) :- numeral(X)
I do understand how it works in theory. It takes the number X and succ increments it. My questions here is, is succ an in-built predicate? Or is there something else going on in this example. Example taken from learnprolognow.org
Then I came across this exercise
pterm(null).
pterm(f0(X)) :- pterm(X).
pterm(f1(X)) :- pterm(X).
It is meant to represent binary, that is 0 is f0(null), 1 is f1(null), 2(10) is f0(f1(null)), 3(11) is f1(f1(null)) etc.
The question asks to define predicate (P1, P2) so that P2 is the successor of P1 by using pterms.
Could someone explain this question in more detail for me?
The way I see it now, I have to traverse back through P1 until I hit the end and then compare it to P2, but I'm not exactly sure about the syntax.
Any hints would be useful
succ is a compound term, not a built-in predicate.
Taking the two clauses in order you have:
numeral(0).
This means numeral(0) is true, i.e. 0 is a numeral
numeral(succ(X)) :- numeral(X)
This means numeral(succ(X)) is true if you can show that numeral(X) is true.
If you ask the query:
?- numeral(succ(succ(0)).
Then prolog will say True: numeral(succ(succ(0)) is true if numeral(succ(0)) is true. And numeral(succ(0)) is true if numeral(0) is true. And we know numeral(0) is true.
If you ask
?- numeral(X).
Then prolog will reply X=0 then X=succ(0) then X=succ(succ(0)) and so on as it finds terms which satisfy your clauses.
Now to answer your pterm question...
First think about the structure you are building. Its a binary number and the outermost term is the least significant bit. Here are some examples for things which are true:
1: succ(f1(null),f0(f1(null))
2: succ(f0(f1(null)),f1(f1(null))
3: succ(f1(f1(null)),f0(f0(f1(null)))
If you look at the examples for 2 and 3 above then you should be able to derive three cases of interest. As a hint the first case is that if the term is of the form f0(X) then the successor is f1(X).
seems that inspecting the top level argument could be enough. Just an hint
psucc(pterm(f0(X)), pterm(f1(f0(X)))).
...
Related
This is probably the most trivial implementation of a function that returns the length of a list in Prolog
count([], 0).
count([_|B], T) :- count(B, U), T is U + 1.
one thing about Prolog that I still cannot wrap my head around is the flexibility of using variables as parameters.
So for example I can run count([a, b, c], 3). and get true. I can also run count([a, b], X). and get an answer X = 2.. Oddly (at least for me) is that I can also run count(X, 3). and get at least one result, which looks something like X = [_G4337877, _G4337880, _G4337883] ; before the interpreter disappears into an infinite loop. I can even run something truly "flexible" like count(X, A). and get X = [], A = 0 ; X = [_G4369400], A = 1., which is obviously incomplete but somehow really nice.
Therefore my multifaceted question. Can I somehow explain to Prolog not to look beyond first result when executing count(X, 3).? Can I somehow make Prolog generate any number of solutions for count(X, A).? Is there a limitation of what kind of solutions I can generate? What is it about this specific predicate, that prevents me from generating all solutions for all possible kinds of queries?
This is probably the most trivial implementation
Depends from viewpoint: consider
count(L,C) :- length(L,C).
Shorter and functional. And this one also works for your use case.
edit
library CLP(FD) allows for
:- use_module(library(clpfd)).
count([], 0).
count([_|B], T) :- U #>= 0, T #= U + 1, count(B, U).
?- count(X,3).
X = [_G2327, _G2498, _G2669] ;
false.
(further) answering to comments
It was clearly sarcasm
No, sorry for giving this impression. It was an attempt to give you a synthetic answer to your question. Every details of the implementation of length/2 - indeed much longer than your code - have been carefully weighted to give us a general and efficient building block.
There must be some general concept
I would call (full) Prolog such general concept. From the very start, Prolog requires us to solve computational tasks describing relations among predicate arguments. Once we have described our relations, we can query our 'knowledge database', and Prolog attempts to enumerate all answers, in a specific order.
High level concepts like unification and depth first search (backtracking) are keys in this model.
Now, I think you're looking for second order constructs like var/1, that allow us to reason about our predicates. Such constructs cannot be written in (pure) Prolog, and a growing school of thinking requires to avoid them, because are rather difficult to use. So I posted an alternative using CLP(FD), that effectively shields us in some situation. In this question specific context, it actually give us a simple and elegant solution.
I am not trying to re-implement length
Well, I'm aware of this, but since count/2 aliases length/2, why not study the reference model ? ( see source on SWI-Prolog site )
The answer you get for the query count(X,3) is actually not odd at all. You are asking which lists have a length of 3. And you get a list with 3 elements. The infinite loop appears because the variables B and U in the first goal of your recursive rule are unbound. You don't have anything before that goal that could fail. So it is always possible to follow the recursion. In the version of CapelliC you have 2 goals in the second rule before the recursion that fail if the second argument is smaller than 1. Maybe it becomes clearer if you consider this slightly altered version:
:- use_module(library(clpfd)).
count([], 0).
count([_|B], T) :-
T #> 0,
U #= T - 1,
count(B, U).
Your query
?- count(X,3).
will not match the first rule but the second one and continue recursively until the second argument is 0. At that point the first rule will match and yield the result:
X = [_A,_B,_C] ?
The head of the second rule will also match but its first goal will fail because T=0:
X = [_A,_B,_C] ? ;
no
In your above version however Prolog will try the recursive goal of the second rule because of the unbound variables B and U and hence loop infinitely.
We are implementing diagnostic tools for explaining unexpected universal non-termination in pure, monotonic Prolog programs—based on the concept of the failure-slice.
As introduced in
the paper "Localizing and explaining reasons for nonterminating logic programs with failure slices", goals false/0 are added at a number of program points in an effort to reduce the program fragment sizes of explanation candidates (while still preserving non-termination).
So far, so good... So here comes my question1:
Why are there N+1 program points in a clause having N goals?
Or, more precisely:
How come that N points do not suffice? Do we ever need the (N+1)-th program point?
Couldn't we move that false to each use of the predicate of concern instead?
Also, we know that the program fragment is only used for queries like ?- G, false.
Footnote 1: We assume each fact foo(bar,baz). is regarded as a rule foo(bar,baz) :- true..
Why are there N+1 program points in a clause having N goals? How come that N points do not suffice?
In many examples, not all points are actually useful. The point after the head in a predicate with a single clause is such an example. But the program points are here to be used in any program.
Let's try out some examples.
N = 0
A fact is a clause with zero goals. Now even a fact may or may not contribute to non-termination. As in:
?- p.
p :-
q(1).
p.
q(1).
q(2).
We do need a program point for each fact of q/1, even if it has no goal at all, since the minimal failure slice is:
?- p, false.
p :-
q(1),
p, false.
q(1).
q(2) :- false.
N = 1
p :-
q,
p.
p :-
p.
q :-
s.
s.
s :-
s.
So here the question is: Do we need two program points in q/0? Well yes, there are different independent failure slices. Sometimes with false in the beginning, and sometimes at the end.
What is a bit confusing is that the first program point (that is the one in the query) is always true, and the last is always false. So one could remove them, but I think it is clearer to leave them, as a false at the end is what you have to enter into Prolog anyway. See the example in the Appendix. There, P0 = 1, P8 = 0 is hard coded.
Recall this proof meta-circular
solve(true, true).
solve([], []).
solve([A|B],[ProofA|ProofB]) :-
solve(A,ProofA),
solve(B, ProofB).
solve(A, node(A,Proof)) :-
rule(A,B),
solve(B,Proof).
Assume that the third rule of the interpreter is altered, while the other rules of the interpreter are unchanged, as follows:
% Signature: solve(Exp, Proof)/2 solve(true, true).
solve([], []).
solve([A|B], [ProofA|ProofB]) :-
solve(B, ProofB), %3
solve(A, ProofA).
solve(A, node(A, Proof)) :-
rule(A, B),
solve(B, Proof).
Consider the proof tree that will be created for some query in both versions. Can any variable substitution be achieved in one version only? Explain. Can any true leaf move to the other side of the most left infinite branch? Explain. In both questions give an example if the answer is positive. How will this influence on the proof?
please help me ! tx
(I have a lot of reservations against your meta-interpreter. But first I will answer the question you had)
In this meta-interpreter you are reifying (~ implementing) conjunction. And you implement it with Prolog's conjunction. Now you have two different versions how you interpret a conjunction. Once you say prove A first, then B. Then you say the opposite.
Think of
p :- p, false.
and
p :- false, p.
The second version will produce a finite failure branch, whereas the first will produce an infinite failure branch. So that will be the effect of using one or the other meta-interpreter. Note that this "error" might again be mitigated by interpreting the meta-interpreter itself!
See also this answer which might clarify the notions a bit.
There are also other ways to implement conjunction (via binarization) ; such that the next level of meta-interpreter will no longer able to compensate.
Finally a comment on the style of your meta-interpreter: You are mixing lists and other terms. In fact [true|true] will be true. Avoid such a representation by all means. Either stick with the traditional "vanilla" representation which operates on the syntax tree of Prolog rules. That is, conjunction is represented as (',')/2. Or stick to lists. But do not mix lists and other representations.
So I have the following working code in Prolog that produces the factorial of a given value of A:
factorial(0,1).
factorial(A,B) :- A>0, C is A-1, factorial(C,D), B is A*D.
I am looking for an explanation as to how this code works. I.e, what exactly happens when you ask the query: factorial(4, Answer).
Firstly,
factorial(0, 1).
I know the above is the "base case" of the recursive definition. What I am not sure of why/how it is the base case. My guess is that factorial(0, 1) inserts some structure containing (0, 1) as a member of "factorial". If so, what does the structure look like? I know if we say something like "rainy(seattle).", this means that Seattle is rainy. But "factorial(0, 1)"... 0, 1 is factorial? I realize it means factorial of 0 is 1, but how is this being used in the long run? (Writing this is helping me understand more as I go along, but I would like some feedback to make sure my thinking is correct.)
factorial(A,B) :- A>0, C is A-1, factorial(C,D), B is A*D.
Now, what exactly does the above code mean. How should I read it?
I am reading it as: factorial of (A, B) is true if A>0, C is A-1, factorial(C, D), B is A*D. That does not sound quite right to me... Is it?
"A > 0". So if A is equal to 0, what happens? It must not return at this point, or else the base case would never be used. So my guess is that A > 0 returns false, but the other functions are executed one last time. Did recursion stop because it reached the base case, or because A was not greater than 0? Or a combination of both? At what point is the base case used?
I guess that boils down to the question: What is the purpose of having both a base case and A > 0?
Sorry for the badly formed questions, thank you.
EDIT: In fact, I removed "A > 0" from the procedure and the code still works. So I guess my questions were not stupid at least. (And that code was taken from a tutorial.)
It is counterproductive to think of Prolog facts and rules in terms of data structures. When you write factorial(0, 1). you assert a fact to the Prolog interpreter that is assumed to be universally true. With this fact alone Prolog can answer questions of three types:
What is the factorial of 0? (i.e. factorial(0, X); the answer is X=1)
A factorial of what number is 1? (i.e. factorial(X,1); the answer is X=0)
Is it true that a factorial of 0 is 1? (i.e. factorial(0,1); the answer is "Yes")
As far as the rest of your Prolog program is concerned, only the first question is important. That is the question that the second clause of your factorial/2 rule will be asking at the end of evaluating a factorial.
The second rule uses comma operator, which is Prolog's way of saying "and". Your interpretation can be rewritten in terms of variables A and B like this:
B is a factorial of A when A>0, and C is set to A-1, and D is set to the factorial of C, and B is set to A times D
This rule covers all As above zero. The reference to factorial(C,D) will use the same rule again and again, until C arrives to zero. This is when this rule stops being applicable, so Prolog would grab the "base case" rule, and use 1 as its output. At this point, the chain of evaluating factorial(C, D) starts unwrapping, until it goes all the way to the initial invocation of the rule. This is when Prolog computes the final answer, and factorial/2 returns "Yes" and produces the desired output value.
In response to your edit, removing the A>0 is not dangerous only for getting the first result. Generally, you can ask Prolog to find you more results. This is when the factorial/2 with A>0 removed would fail spectacularly, because it would start going down the invocation chain of the second clause with negative numbers - a chain of calls that will end in numeric overflow or stack overflow, whichever comes first.
If you come from a procedural language background, the following C++ code might help. It mirrors pretty accurately the way the Prolog code executes (at least for the common case that A is given and B is uninstantiated):
bool fac(int a, int &b)
{
int c,d;
return
a==0 && (b=1,true)
||
a>0 && (c=a-1,true) && fac(c,d) && (b=a*d,true);
}
The Prolog comma operates like the sequential &&, and multiple clauses like a sequential ||.
My mental model for how prolog works is a tree traversal.
The facts and predicates in a prolog database form a forest of trees. When you ask the Prolog engine to evaluate a predicate:
?- factorial(6,N).
the Prolog engine looks for the tree rooted with the specified functor and arity (factorial/2 in this case). The Prolog engine then performs a depth-first traversal of that tree trying to find a solution using unification and pattern matching. Facts are evaluated as they are; For predicates, the right-hand side of the :- operator is evaluated, walking further into the tree, guided by the various logical operators.
Evaluation stops with the first successful evaluation of a leaf node in the tree, with the prolog engine remembering its state in the tree traversal. On backtracking, the tree traversal continues from where it left off. Execution is finally complete when the tree traversal is completed and there are no more paths to follow.
That's why Prolog is a descriptive language rather than an imperative language: you describe what constitutes truth (or falsity) and let the Prolog engine figure out how to get there.
I'm new to Prolog and I'm trying to resolve this exercise:
Define a predicate greater_than/2 that takes two numerals in the notation that we introduced in this lecture (i.e. 0, succ(0), succ(succ(0))...) as arguments and decides whether the first one is greater than the second one. E.g:
?- greater_than( succ(succ(succ(0))), succ(0) ).
yes.
?- greater_than( succ(succ(0)), succ(succ(succ(0))) ).
no.
This is my answer so far:
greater_than(X, 0).
greater_than( succ(succ(X)), succ(Y) ).
but of course doesn't work properly, so I'm asking anyone for help.
Thanks.
As you are looking for a recursive solution, you have to provide a base case and a recursive step.
The base case you provided is almost right. However it fails because it will succeed for example when both numbers are zero. It should succeed only when the left side is of the form succ(_) and the right side is zero.
The recursive step should take an element from each side and apply recursion.
Therefore this should work:
greater_than(succ(_), 0).
greater_than(succ(X), succ(Y)):-
greater_than(X, Y).