AI Prolog exercise [closed] - prolog

This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 9 years ago.
Here is the Question following:
For this question we consider binary expression-trees whose leaves are either of the form tree(empty, Num, empty) where Num is a number, or tree(empty, z, empty) in which case we will think of the letter z as a kind of "variable".
Every tree is either a leaf or of the form tree(L, Op, R) where L and R are the left and right subtrees, and Op is one of the arithmetic operators '+', '-', '*', '/' (signifying addition, subtraction, multiplication and division).
Write a predicate tree_eval(Value, Tree, Eval) that binds Eval to the result of evaluating the expression-tree Tree, with the variable z set equal to the specified Value. For example:
?- tree_eval(2, tree(tree(empty,z,empty),
'+',tree(tree(empty,1,empty),
'/',tree(empty,z,empty))), Eval).
Eval = 2.5 ;
false.
?- tree_eval(5, tree(tree(empty,z,empty),
'+',tree(tree(empty,1,empty),
'/',tree(empty,z,empty))), Eval).
Eval = 5.2 ;
false.
Some good ideas?
Could we achieve it without using cut(!)?
Thanks guys!

It is a shame you wouldn't even try to solve it before asking for help.
Your question almost directly translates to a solution. When there is a Num in the middle of the tree:
tree_eval(_Value, tree(empty,Num,empty), Num).
When there is a variable:
tree_eval(Value, tree(empty,z,empty), Value).
And the general case:
tree_eval(Value, tree(tree(LL,LOp,LR),Op,tree(RL,ROp,RR)), Eval) :-
tree_eval(Value, tree(LL,LOp,LR), LEval),
tree_eval(Value, tree(RL,ROp,RR), REval),
Expr =.. [Op,LEval,REval], % is there an easier way to do this?
Eval is Expr.
Now as you notice, this solution has no cuts. They are not necessary, because at a time, only one of the three clauses can be true. For one of the clauses, however, I couldn't come up with a way to make the head unambiguous. This might be of help.

Related

Prolog and limitations of backtracking

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.

Get the length of a list in prolog in a non-recursive way

I have the following code for getting the length of a list in prolog, it works recursively.
Is there any other way for getting the length?
len([], 0).
len([H|T], N) :-
len(T, NT), N is NT + 1.
Any suggestions would be appreciated.
You are asking the wrong question :)
But seriously: the only sensible way of finding the length of a list is to use the built-in length/2. How it is implemented is irrelevant -- more important are its semantics:
?- length([a,b], 2).
true.
?- length([a,b], 4).
false.
?- length([a,b,c], Len).
Len = 3.
?- length(List, 3).
List = [_G937, _G940, _G943].
?- length(List, Len).
List = [],
Len = 0 ;
List = [_G949],
Len = 1 ;
List = [_G949, _G952],
Len = 2 . % and so on
Either way, it doesn't get simpler than that. Any other way of finding the length of a list, or checking for the length of a list, or creating a list of a certain length, or enumerating lists of increasing length is going to be less "simple" than using length/2.
And then: learning Prolog means learning how length/2, and the other nicely declarative built-ins can be used.
Repeating an element N times
Splitting a list into segments of some length
Exactly one pair in a list
Rotate a list
I am sure you can think of many other uses of length/2.
Here is an iterative solution that uses repeat/0 predicate:
getlength(L,N) :-
retractall(getlength_res(_)),
assert(getlength_res(0)),
retractall(getlength_list(_)),
assert(getlength_list(L)),
repeat,
(
getlength_list([]), !, getlength_res(N)
;
retract(getlength_res(V)), W is V + 1, assert(getlength_res(W)),
retract(getlength_list([_|T])), assert(getlength_list(T)), fail
).
This solution creates and retracts facts getlength_res/1 and getlength_list/1 as it walks through the list, replacing the old list with a shorter one, and the old number with a number that is greater by one at each iteration of repeat/0. In a sense, the two dynamically asserted/retracted facts behave very much like assignable variables of imperative languages.
Demo.
In general, iterative solutions in Prolog are harder to read than their recursive counterparts. This should come as no surprise, considering that anything that has an effect of an assignment statement of an imperative programming language goes against the grain with Prolog's design philosophy.
Sorry I could not resist to try out this "challenge":
Input=[a,b,b,b,b,b,b,b,b,a,b,c,d,f], between(1,inf,K),findall( _,between(1,K,_),FreeList), ( FreeList=Input,!,true).
findall/3 is doing the behind-the-scenes recursion, code is making unifications of lists FreeList and Input until they unify

prolog using recursion to find successor

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)))).
...

Recursive procedure explanation

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.

Prolog programming - what is the program regarding the next tasks? [closed]

This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 10 years ago.
Could you help me regarding the next three Prolog programs?
Summary of the elements in a list, and check that is divided or not divided with 3?
For example, the list is [1, 2, 3] --> and the sum of the element is divided with 3, because 1+2+3=6, and 6/3=2 --> so the output should be true.
If the 7 is in a list, doubles it. For example: the input list --> [1,7,3,7,7], the outputs should be [1,7,7,3,7,7,7,7].
If the 7 is in a list, change it for 2,7,2. For example: the input list -->[1,7,2,1], the output should be [1,2,7,2,2,1]
What is the program and how to test it with SWI-Prolog?
Thank you in anticipation!
I will give you a couple of tips:
You need a) to calculate the sum, b) check whether it divides by 3. If you use SWI-Prolog there is a predicate sum_list in the library lists that does a) and the ... is ... mod ... construction to solve b) If you need to use recursion rather than the built-in predicate to calculate the sum:
sum([X|Xs], Acc, Sum) :- Acc1 is Acc + X, sum(Xs, Acc1, Sum).
sum([], Acc, Acc).
sum(List, Sum) :- sum(List, 0, Sum).
and 3. These are recursive procedures. You should traverse the list and if 7 is encountered you should replace it with 7,7 for question 2 and with 2,7,2 for question 3.
traverse_list([],[]).
traverse_list([7|Xs], [7,7|Ps]) :-
!,
traverse_list(Xs,Ps).
traverse_list([X|Xs], [X|Ps]) :-
traverse_list(Xs,Ps).
Think about modifying this fragment for 3.
I'd recommend giving it a little thought and figuring it out on your own. That said, I'll give you something to help get started:
1) I'm assuming your instructor wants to see you do the recursion rather than use the built-in sum_list predicate. That would look something like this:
sum([FirstNum | Rest], Sum) :-
sum(Rest, Sum1),
Sum is FirstNum + Sum1.
Then use the "mod" operator to check divisibility. Remember to include a base case for when the recursion reaches the empty set []. If you can understand this, the rest should be easy. Good luck.

Resources