I have written a program to evaluate a post-fix expression in prolog recursively from an expression list. For example, given the following list:
[+,1,2]
It should return 3. They way I have constructed my predicate is to call itself recursively until it reaches the end of the list so that it reads values backwards. (the same as reading this list from left to right:[2,1,+]).
My problem is that when I try to return more than one value through the recursive calls all the values suddenly disappear.
Here's the code:
eval_list([Head|Tail],_,Result):-
Tail==[], % last element of list
Result=Head,
write(Head),
write(' was stored in Result!\n').
eval_list([Head|Tail],Store1,Result):-
eval_list(Tail,Store2, NewResult),
(\+integer(Store2))
->
% if no integer is bound to Store2, bind Store1 to Head
Store1=Head,
Result is NewResult,
write(Head),
write(' is stored value!\n')
; (integer(Store2)) ->
% if an integer is bound to store2, we perform operation specified by the Head with the stored number
X is Store2+NewResult,
Result is X,
write('performed operation!\n')
;
% if doesnt catch either of these states the program is broken
( print('something broke\n'),
print(Store1),
nl,
print(Store2),
nl,
print(Head),
nl,
print(Result),
nl
).
I get the following output:
?- eval_list([+,1,2],X,Result).
2 was stored in Result!
1 is stored value!
something broke
_G1162
_L147
+
_G1163
true.
I don't understand why my values disappear, or if there is a better way to evaluate the list.
Some advice on your programming technique. You should use head matching and unification instead of explicit unification in the body of your predicate definitions, and if-else constructs. You should also avoid not tail-recursive recursion, unless your algorithm is inherently recursive (in-order tree traversal, for example). This will make the code easier to write, read, and understand. Right now, I don't even feel like debugging your code, but it looks like your Store2 would never be bound to an integer, and is always going to be an unbound variable, no matter what input your program has.
Now to your program. It is not clear what you are trying to achieve. If you only want to evaluate list of the form [Arithmetic_operator, Operand1, Operand2], it would be much easier to write:
arith_eval(Expression_list, Result) :-
Arithmetic_expr =.. Expression_list, % look up what =.. stands for!
Result is Arithmetic_expr.
I don't see the need for this overly complicated approach you are using.
If you want to be able to evaluate arbitrarily complex expressions, written in post-fix, with fixed operator arity (so you can say 2, 3, +, but not 2, 4, 1, +, for a sum of 7):
Read one element from your input
Push the element to the top of the stack
Try to reduce the stack:
pop operator and operands, if on top of the stack
evaluate
push result back on the top of the stack
When input is empty, your stack is your result
You could explicitly define the effect of different operators (here, only + and -) like this:
eval_stack([+,A,B|Tail],[Result|Tail]) :-
number(A), number(B),
!,
Result is B + A.
eval_stack([-,A,B|Tail],[Result|Tail]) :-
number(A), number(B),
!,
Result is B - A.
eval_stack(Stack,Stack).
Note how either an operator matches the top of your stack, and is applied when there are operands below it, pushing the result back on the stack, or the stack is left unchanged.
And you can push from your input to your stack:
evaluate([Next|Rest], Stack, Result) :-
eval_stack([Next|Stack],NewStack),
evaluate(Rest,NewStack,Result).
evaluate([],Result,Result). % end of input
So now you could call this with:
?- evaluate([2,3,+,3,6,-,+],[],Result).
Result = [2].
?- evaluate([2,3,4,-,-,5,+],[],Result).
Result = [8].
?- evaluate([2,3,4,-,-,5,+,1,3,2,-],[],Result).
Result = [1,1,8].
So these two predicates, evaluate(Input,Stack,Result), and eval_stack(Stack,NewStack) is all you would need for evaluating a valid post-fix arithmetic expressions with fixed-arity operators only.
Related
We are not supposed to use any of the functions other than the ones listed below:
A single clause must be defined (no more).
+
,
;
.
!
:-
is
Lists
Head and tail syntax for list types
Variables
For example sumlists([1,2,3,5,7],11) then the program execution should print TRUE. Because 1+3+7 (any three)=11 (given N value).
Ideally, we either get an element or don't, as we go along the input list; and we stop either on having reached the needed sum, or having surpassed it, or when the list has been exhausted.
But we can only have one clause one predicate here, and only use certain primitives, so instead we sneakily use + both symbolically, to gather the information for summation, and as an arithmetic operation itself:
sumlists(L, N) :-
N = X+A+B+C, X is A+B+C, !
; L = [H|T], sumlists(T, N+H)
; L = [H|T], sumlists(T, N).
I'm very new to prolog and I am trying to write a little program that, given a list, returns the sum of the list's elements. Following all the examples I've seen led me to a solution that looks like this:
addup([],0).
addup([FirstNumber | RestOfList], Total) :-
addup(RestOfList, TotalOfRest),
Total is FirstNumber + TotalOfRest.
But when I test that solution with these values:
?- addup([1,2,3,4],0).
I just get garbage values from it like _34521.
Then I tried a second solution that looks like this:
sum([], 0).
sum([H|T], N):-
X is H+N,
sum(T, X).
This one is able to add up the numbers correctly, but it is unable to pass the final value of X, which is the true answer, into N. So for the test case:
?- sum([1,2,3,4], 0).
I get an answer of 6, the final value of N, and the second-to-last value of X, instead of 10, the final value of X. Any help and/or explanations of why neither of these solutions work would be greatly appreciated. Thanks.
Firstly, the sum of an empty list is 0 - this is the base case, which you already had.
Secondly, the sum N of an element H and a list T is the sum of the list T added to H. Prolog operates on unification, so this says that N is unified with the sum of H and T, where the sum of T is unified with X using sum(T,X).
sum([], 0).
sum([H|T], N):-
sum(T, X),
N is X + H.
This gives:
?- sum([1,2,3,4],N).
N = 10.
In your original question, ?- sum([1,2,3,4], 0). actually says "this is true if the sum of the list [1,2,3,4] is 0" - you need to pass a variable as the second argument to sum to be unified with the answer.
Further information:
_34521 is a representation of an unbound variable - this says that there is a variable, but that it has not yet been unified with a value.
Secondary consideration:
For a suitably long list, the implementation above will run out of stack space, as each frame of the recursion must be stored, so that the addition can happen from the bottom up. In order to prevent a stack error, we can use a tail-recursive accumulator like so:
sum(L, N):-
sum(L, 0, N).
sum([],N,N).
sum([H|T],A,N) :-
A1 is A + H,
sum(T,A1,N).
... which retains the signature of the original method, wrapping sum/3. As there is no choice-point in the body of the rule (given that A + H is always the same for a given A and H, and the list is either empty or not), Prolog will discard each frame as it leaves scope (as there is nothing more to be done with it) and, on completion, will return to the original caller.
Simplified stack for sum([1,2,3],N) in each instance:
non-tail-recursive:
rest-of-stack
rest-of-stack,sum([1|[2,3]],_1001)
rest-of-stack,sum([1|[2,3]],_1001),sum([2|[3]],_1002)
rest-of-stack,sum([1|[2,3]],_1001),sum([2|[3]],_1002),sum([3|[]],_1003)
rest-of-stack,sum([1|[2,3]],_1001),sum([2|[3]],_1002),sum([3|[]],_1003),sum([],0)
rest-of-stack,sum([1|[2,3]],_1001),sum([2|[3]],_1002),sum([3|[]],3)
rest-of-stack,sum([1|[2,3]],_1001),sum([2|[3]],5)
rest-of-stack,sum([1|[2,3]],6)
rest-of-stack
tail-recursive:
rest-of-stack
rest-of-stack,sum([1,2,3],_1001)
rest-of-stack,sum([1|[2,3]],0,_1001)
rest-of-stack,sum([2|[3]],1,_1001)
rest-of-stack,sum([3|[]],3,_1001)
rest-of-stack,sum([],6,6)
rest-of-stack
Note that the tail-recursive stack has a limited depth for any length of list (dependent on what is calling it), where the non-tail-recursive stack goes to a depth directly proportional to the length of the list.
Thus, a call such as N is 10^7,length(L,N),maplist(=(1),L),sum(L,N). (as raised by #false) will likely fail without tail-recursion, and likely succeed with it.
I've written a small Prolog program that's supposed to check a list and see whether the head Ha is greater than K, if it is, it is supposed to append it to a list R and after checking the whole list give back R which then would consist of bigger than K integers.
This code returns R = [].
teilliste_grK([],_,_).
teilliste_grK([Ha|Ta], K, R) :-
Ha =< K,
teilliste_grK(Ta,K,R).
teilliste_grK([Ha|Ta], K, R) :-
Ha > K,
append(R, [Ha], C),
teilliste_grK(Ta, K, C).
Any help?
you should write out how do you want to call this predicate with some sample data, and what you're expecting to get back from it. this is important. :)
okay, I'll do it: teilliste_grK([1,4,2,5,3,6],3,X) should succeed, instantiating X to [4,5,6], correct? Now try to see which of the clauses does it match with.
So it matches with the second, 1 is indeed =< 3, and the last line says, continue without the head element (that was smaller than the given K), and whatever R we get from there, is our R as well – R is R after all.
Good. So when we come to 4 next, what happens? The 2nd clause matches but is then rejected with 4 =< 2. Good. On to the third clause.
Again it matches, and the inequality holds, but then you do something strange. You first say that C is one element longer than R, and that C you get from the shorter list - the tail Ta of your input. Whatever you set your R in the final clause (the first one), this just can't be.
You want your C to be shorter than R, which is to start with the same head Ha which has just passed the test, so the arguments just need to be put in a different order:
append([Ha], C, R),
(you can write this shorter and simpler though, without any call to append – what is it?).
Now what about that final (3rd, i.e. []) clause? If you call teilliste_grK([],3,X), what should X be?
Ho do I square numbers in a list in prolog?
The list can contain numbers, atoms and lists.
for example: [a,b,2,3,4,[3],[c,d,9]] and the answer should be [a,b,4,9,16,[3],[c,d,9]].
As we see in the answer it should be a shallow squaring of the values in the list.
2->4
3->9
4->16
What I have tried so far,
square([],X).
square([A|B],X):-number(A), A is A*A, square(B,X).
X will contain squared values. Base case is when empty list is received. I check if head (A) is a number then I go ahead square the number and change A to A * A. Then go ahead and call the square function for remaining part B.
Please suggest where I am doing wrong.
EDIT: Correct answer as follows. By aBathologist. Please read his comment for detailed explanation.
squared_members([], []).
squared_members([L|Ls], [SqrdL|SqrdLs]) :-
number(L),
SqrdL is L * L,
squared_members(Ls, SqrdLs).
squared_members([L|Ls], [L|SqrdLs]) :-
\+number(L),
squared_members(Ls, SqrdLs).
And
squared_members([], []).
squared_members([L|Ls], [M|Ms]) :-
( number(L)
-> M is L * L, squared_members(Ls, Ms)
; M = L, squared_members(Ls, Ms)
).
We're defining a predicate which describes the relationship between one list, A, and another list, B: B should have all the same elements as A, except that any number in A should be squared in B.
Where you've gone wrong:
Your ground condition, square([],X), says that when A is empty, then B is anything (so, for instance, even something like square([], 15) is true). But this doesn't capture the meaning we're after, since the second argument should be a list with the same number of members as the first. That is, when the first list is empty then the second list should be empty.
The same problem occurs with your recursive rule, since, at each iteration, an undetermined variable is passed along, and there is never anything said about the relationship between the first list and the second.
This rule will only succeed if the first element of alist is a number. In the case where the first element is, e.g., a (like in your example), number(a) will be false. Since there are no additional rules for the predicate, it will simply be false unless every member of the first list is a number.
Variables in Prolog must always have the same, consistent value throughout the context in which they appear. They function like variables in arithmetic formula. The formula a + b - b = a is true for any values of a and b but *only if a and b are each assigned one, consistent value throughout the equation. The same is true in Prolog statements of the form <variable> is <expression>. What you've written says a = a * a which cannot be the case.
*What you're definition says is, roughly, this: The list B is a squared version of the list A if A is an empty list and B is anything OR if the first element of A is a number, and that number is equal to itself squared, and B is a squared version of the rest of A.
Here's one possible solution:
squared_members([], []).
squared_members([L|Ls], [SqrdL|SqrdLs]) :-
number(L),
SqrdL is L * L,
squared_members(Ls, SqrdLs).
squared_members([L|Ls], [L|SqrdLs]) :-
\+number(L),
squared_members(Ls, SqrdLs).
Notice that this definition is able to establish a meaningful relationship between the two lists by having them either share variables, or contain elements related by a chain of relations between variables (i.e., SqrdL is related to L by virtue of being L * L). This definition has one more clause then yours, which enables it to take account of the members of a list which are not numbers: those are added to the second list unaltered.
An alternative definition, using If-Then-Else notation for cleaner expression, would be the following:
squared_members([], []).
squared_members([L|Ls], [M|Ms]) :-
( number(L)
-> M is L * L, squared_members(Ls, Ms)
; M = L, squared_members(Ls, Ms)
).
I'm new to prolog and I'm trying to figure out how I can use if/else statement and recursion. To illustrate, I've written a simple prolog program. The program is useless (in that its functionality is useless), but it helps me illustrate my problem. The program takes a list, examines the head of the list, sees if it's the last element; if it's not, it adds the head to a temporary list variable and runs the program in recursion using the Tail of the list. It should output the list in the end. The program:
gothrough([H|T], B, C):-
append(B,H,B),
( (T == [])
-> C=B
; gothrough(T, B, C)
).
The call: gothrough([sample, phrase, here], [], C).
Expected output: C = [sample, phrase, here]
Current output: no
Any help on what I'm doing wrong?
Thanks!
From your comments I understand that you misunderstand how append (and Prolog in general) works.
This is not true at all: "if B = [yesterday] and H = [today], then append(B, H, B) = [yesterday, today]".
append(B, H, B) means "appending H to B yields B again". This is only possible if H is an empty list.
The key thing to understand is that both Bs in append(B, H, B) are the same, they must have the same value. It's like variables in algebra - all Xs in an equation means the same value.
You should use different name for the output variable, like append(B, H, Bnew) - then it will make more sense.
The first problem is append(B, H, B) which for most inputs doesn't make sense.
The second problem is that the consequence and alternative of an if-then-else, i.e. the parts after -> and after ; must both be Prolog goals (statements). C is not a goal. You may have meant C=B, though it's hard to tell because I find it hard to understand what your program is doing.
You're getting a no because append(B,H,B) fails unless H is []; remember, these are clauses, not assignments. And since you never bind anything to C, it will never have a value in it if your statement was ever proved.
This will accomplish your task:
gothrough([],L,L).
gothrough([H|T], B, C) :- gothrough(T,B,Cx), append([H],Cx,C).
This can be done even more simply:
gothrough([], []).
gothrough([H|T], [H|X]) :-
gothrough(T, X).
The first rule matches your empty list condition, which then forces the end of the recursion/the list to be built.
The second rule matches everything but an empty list, in which case the head H is appended onto X, where X is the result of list obtained from recursing the tail. ie. you don't need to use the append predicate - list appending is built into prolog.
?- gothrough([simple, phrase, here], X).
X = [simple, phrase, here].
This solution also uses one less variable.