Prolog - evaluating algebraic expressions [duplicate] - prolog

This question already has an answer here:
Evaluating an algebraic expression
(1 answer)
Closed 9 years ago.
This is a test review question that I am having trouble with. How do you write a method to evaluate an algebraic expression with the operators 'plus', 'minus' and 'times'. Here are some test queries:
simplify(Expression, Result, List)
?- simplify(plus(times(x,y),times(3 ,minus(x,y))),V,[x:4,y:2]). V = 14
?- simplify(times(2,plus(a,b)),Val,[a:1,b:5]). Val = 12
?- simplify(times(2,plus(a,b)),Val,[a:1,b:(-5)]). Val = -8
All I was given were these sample queries and no other explanation. But I am pretty sure the method is supposed to dissect the first argument, which is the algebraic expression, substituting x and y for their values in the 3rd argument (List). The second argument should be the result after evaluating the expression.
I think one of the methods should be simplify(V, Val, L) :- member(V:Val, L). Ideally there should only be 4 more methods... but I'm not sure how to go about this.
What I have so far but I don't know what the body should be:
simplify(Var, Value, Lst) :- member(Var:Value, Lst).
simplify(plus(Var), Value, Lst) :-
simplify(minus(Var), Value, Lst) :-
simplify(times(Var), Value, Lst) :-
I am not sure what the 5th method should be.

I suspect you've allowed yourself to get snowed by complex examples. You're just missing one base case and all the inductive cases are really simple. You just need some simpler examples. For starters, what should this return?
?- simplify(3, Val, []).
Yeah, Val = 3. So let's add that missing base case:
simplify(Num, Num, _) :- number(Num).
The key insight to the inductive casess is that plus, minus and times all have the same recursive binary structure. You can recursively apply simplify to both sides to achieve to evaluate things. Let's try another simple example:
?- simplify(times(3, 3), Val, []).
We want Val = 9. All we need to do is figure out what the left and right values are and multiply them together. So it will wind up looking like this:
simplify(times(Left, Right), Value, Lst) :-
simplify(Left, LeftVal, Lst),
simplify(Right, RightVal, Lst),
Value is LeftVal * RightVal.
You want to pass Lst on to the recursive invocations so they can look up variables too. From here you should be able to extrapolate what the plus and minus cases are going to look like. You really shouldn't need cases that look like plus(X) since that only has one argument.
The magic of Prolog is that this is really all you have to do. Recursion will take care of your complex examples as soon as you have the simple ones working. Try it. :)
Hope this helps!

Related

Why am I getting Type error: `[]' expected, found `[21,3,4,5,6,7,8]' (a list) ("x" must hold one character) with maplist/3 prolog?

I am new to Prolog. I want a predicate that takes a list, process it with maplist/3 creating a corresponding list with zeros in place of numbers less than mean and 1 for number above the mean. I then want a second predicate to sum the 1's to find out how many numbers are above the mean. This second predicate then returns this number which corresponds to total numbers above the mean.
I know the code below works fine:
numAtOrAboveMean(Mean, Num, Val) :- Num > Mean -> Val is 1; Val is 0.
maplist(numAtOrAboveMean(Mean), [], List), sumlist(List, Below).
When I modified it to this, I get a type erros that expected [] but found a list. The comments correspond to how I think the predicate behavior is.
nGMean(Mean, Num, Val) :- Num > Mean -> Val is 1; Val is 0.%sorts list
nGMean([], _ , []). %takes a list, a constant, relates to a list
nGMean(L, Mean, List) : - maplist(nGMean(Mean), L, List). %maplist call sort
Then to sum I will use a second predicate. Something like this:
sumtotal(L,V) :- mean(L, M), M2 is M, nGMean(L, M2, List), sum(List, V).
Which is not working probably mostly because nGMean is throwing an error. nGMean full error is shown below:
So my question is, why am I getting that type error on the nGMean predicate?
Edit -As requested in comments below is the entire thing. As I explained that is the only part because I am testing it separately.
Thank you for answers. Next time I will post complete code.Or make clear that I just want to trouble shoot one predicate.
Maplist for numAtOrAboveMean
Full Pic of code on Editor
You should post complete code that can just be copied and run. In what you have posted, mean/2 and sum/2 are not defined.
(Addition:) the reason for the error seems to be that you are comparing a value and a list (2<[2,3|...]). The reason this happens is because your first clause for nGMean/3 has Mean as first parameter, whereas the other clauses has the list, i.e. the list becomes Mean which is used in the comparison (Num > Mean). I'm not sure how > becomes <.
Also, calling maplist/3 on an empty list does not make sense.
A recursive predicate should have two clauses. A recursive clause that (typically) does something with the head of the list and then calls recursively on the tail, and a base case (empty list).
nGMean([Num|Nums],Mean,[Val|List]) :-
( Num > Mean ->
Val = 1
; Val = 0 ),
nGMean(Nums,Mean,List).
nGMean([],_,[]).
With this definition I get the same output as your first two lines above, so I believe this is what you wanted.
(Earlier addition: you only need to use is when the right-hand side contains mathematical calculations. To just set a value, = is fine.)

Arithmetic expression in prolog solving

given an expression:
(x*0+6)*(x-x+3+y*y) and value of y:2 the Predicate should give only one
solution (x*0+6)*(x-x+3+4).
when 6*(3+x*x) and x:2 is given then it should give the output 42 .
I have been coding for hours and i could manage to get only the second part of it .my code is posted below .can some one help me with solution .
partial_eval(Expr0, Var,Val, Expr) :-
evaluate(Expr0,[Var:Val],Expr).
evaluate(Exp, LstVars, Val) :-
analyse(LstVars, Exp, NewExp),
Val is NewExp.
analyse(LstVars, Term,R) :-
functor(Term, Term, 0), !,
( member(Term : V, LstVars)
-> R = V
; R = Term ).
analyse(LstVars, Term, V) :-
functor(Term, Name, _),
Term =.. [Name | Lst],
maplist(analyse(LstVars), Lst, LstV),
V =.. [Name|LstV].
This problem can be broken down into two: One is substituting in values for variables. The other is recursively evaluating arithmetic subexpressions. Prolog is nondeterministic but both of these operations are deterministic, so that's something to keep in mind while implementing them.
You seem to have a good generic recursion structure (using =..) for the substitution part. For the arithmetic evaluation part you may find it easier to use + and * terms in the recursion. Hope that helps you get started, ask if you get stuck and need more advice.

Explain what this Prolog program does?

I am working on Prolog and I came across the below program. When I execute this program with a query for example: mysterious([2,3,4,5,6,7,8],L), it gives me the answer 20. I don't understand the flow of getting this result. Can anyone help me to understand this code?
How does it produce the answer 20 for the above mentioned query?
mysterious([],0).
mysterious([X],X).
mysterious([X,Y|Xs], Res) :-
mysterious(Xs, Res1),
Res is X + Res1.
Because this is such a basic program, I will give you a hint. First off, this:
foo([]).
foo([X]).
foo([X,Y|Rest]) :-
foo(Rest).
could be also written as:
foo([]).
foo([First|Rest]) :-
bar(Rest, First).
bar([], Last).
bar([This|Rest], Prev) :-
foo(Rest).
It is unnecessarily verbose, but more explicit. In your case, however, it makes something obvious:
mysterious([], 0).
mysterious([X|Rest], Result) :-
myst_1(Rest, X, Result).
myst_1([], Result, Result).
myst_1([_Y|Rest], X, Result) :-
mysterious(Rest, Result1),
Result is X + Result1.
Something which you did not mention in your question is that the compiler must have given you a "singleton variable" warning on the Y in the last clause of mysterious/2. This should have been a strong indication of what is going on already.
I can help you by commenting lines, maybe you will understand the prolog a little more, let's start:
Prolog programs describe relations, defined by means of clauses. Pure Prolog is restricted to Horn clauses. There are two types of clauses: facts and rules. (by wikipedia)
% comment in prolog starts with '%'
mysterious([],0). % its called 'predicate', something like functions in imperative
% languages. it has two arguments: [], and 0. and it is ended
% by dot (.). Clauses with empty bodies are called facts.
% (this is fact).
mysterious([X],X). % is actually a "rule" that says, "if the list has one element,
% then the result is just that element". (by #mbratch)
mysterious([X,Y|Xs], Res) :- % now, when argument 1 is list which looks like
% [SomeElement, NextElement|LastElements],
mysterious(Xs, Res1), % call 'mysterious' with only LastElements
% and variable Res1 (skip first two elements of list)
Res is X + Res1. % then add first element to Res1.
% it calculates the sum of every second element of list, beginning on first.

Prolog, Returning list from 1 to N

Basically I'm working on a bigger problem, but how would I return a list from 1 to a number n? I'm new to this and a little confused. Also, would it be possible to pass this as a parameter in a function call?
like check(newlist(1, N), [L | Rl]);
where newlist is a function call that returns the list between 1 and N?
Sorry if my terminology is off. It seems like a pretty basic problem but I'm still learning and getting down the concept of Prolog.
In Prolog, you don't really have functions that return values. You have predicates that unify variables. With that in mind, you'd write something like this:
range(1, N, ResultOfRange),
check(ResultOfRange, [L, Rl]).
With that said, think about the base condition of range and then figure out how you'd build on that to make a predicate yielding a whole range of numbers.
Check your Prolog' library. For instance, in SWI-Prolog there is numlist/3. You can pass a predicate 'by name', assuming the callee will invoke it by means of call/N.
check(ListBuilder, N) :-
call(ListBuilder, 1, N, L),
...
main :-
check(numlist, 10),
...

Do you really need to convert Truths to values in Prolog?

I wrote a bubble sort in Prolog (code below). It works but it smells. I'm quite new to prolog. Here's the problematic part:
% Problem: convert the true value to something
% I can actually use.
sorted_value(X,X) :- sorted(X).
sorted_value(X,[]) :- not(sorted(X)).
It's weird I need to use this function to convert a True value to something (in this case, []) and False to another thing in order to use them. Isn't there a cleaner way?
% Bubble Sort a list.
% is the list sorted?
sorted([]).
sorted([Head|[]]).
sorted([First|[Second|Rest]]) :-
min(First,Second,First),
sorted([Second|Rest]).
% swap all pairs in the list that
% needs to be swapped
bubble_sort_list([], []).
bubble_sort_list([Head|[]],[Head]).
bubble_sort_list([First|[Second|Rest]], [One|Solution]) :-
min(First,Second, One),
max(First,Second,Two),
bubble_sort_list([Two|Rest],Solution).
% Problem: convert the true value to something
% I can actually use.
sorted_value(X,X) :- sorted(X).
sorted_value(X,[]) :- not(sorted(X)).
% Repeatedly call bubble_sort until
% the list is sorted
bubble_sort_helper([],List, Solution) :-
bubble_sort_list(List, SortedList),
sorted_value(SortedList, Value),
bubble_sort_helper(Value,SortedList, Solution).
bubble_sort_helper(A,List,List).
% this is what you call.
buuble_sort(List,Solution) :-
bubble_sort_helper([],List,Solution).
Every predicate call either succeeds (possibly several times) or fails. If you think declaratively and really describe what a sorted list is, there would only rarely seem to be a need to explicitly represent the truth value itself in a program. Rather, it would typically suffice to place a predicate call like "ascending(List)" in a Prolog program to describe the case of a sorted list. There seems to be no advantage to instead call a predicate like "ascending(List, T)" and then use T to distinguish the cases. Why not use the implicit truth value of the predicate itself directly? If you really need to reify the truth value, you can for example do it like this to avoid calling ascending/1 twice:
ascending(Ls, T) :-
( ascending(Ls) -> T = true
; T = false
).
Notice how the truth of ascending/1 is used to distinguish the cases.

Resources