In Prolog, I made a Max function, however, I am trying to compare the number it returns to others, and can tell that it isn't giving me the right number. My list will be [2,2,1,2] so my max should be 2, but when I compare the max found with 2, it fails.
My code looks like this:
maximumElement([X], X).
maximumElement([H|T], MaxFound):-
maximumElement(T, MaxOfTail),
MaxFound = max(MaxOfTail, H).
My problem could also be where I am comparing the numbers, but right now I have changed it so that that predicate looks like this when called:
maximumElement(List, MaxFound),
checkIfTwo(MaxFound, MaxFound).
And this in it's predicate:
checkIfTwo(2,2).
Since I am comparing it like that, it seems weird that I would get false, because I am comparing the same numbers, so I think it has to be a problem with my compare or finding the max.
As said by everyone in the comments it is enough to say
maximumElement([X], X).
maximumElement([H|T], MaxFound):-
maximumElement(T, MaxOfTail),
MaxFound is max(MaxOfTail, H).
but I write answer anyway because you have issues, it is not just any element, it must be number or arithmetic expression because you use is max(), so name is not too great, and also you get choicepoint even though there is no choices left. Look:
?- maximumElement([1+2,2], Max).
Max = 3 ;
false.
So maybe you can instead write:
max_arith_expr([X|Xs], Max) :-
max_arith_expr(Xs, X, Max).
max_arith_expr([], X, X).
max_arith_expr([X|Xs], X0, Max) :-
max_arith_expr(Xs, X, Max0),
Max is max(X0, Max0).
But why really is it non-tail-recursive? Maybe necessary, or maybe not? Because if you already have three arguments you can just accumulate maximum
max_arith_expr([], Max, Max).
max_arith_expr([X|Xs], Max0, Max) :-
Max1 is max(X, Max0),
max_arith_expr(Xs, Max1, Max).
But I am afraid this now looks exactly like what you alrady had here in the library so I don't know if this is somehow good or bad or both?
Related
I am trying to implement some simple predicates, something like my_length or my_append.
It is considered easy for me if we knew beforehand that we wanted to find the length of a list, or we wanted to append two lists. (i.e. I know what is input, what is output).
In Prolog, it is possible to do thing in other ways. Like my_length(L, 3), or my_append(A,B,[1,2,3]).
Sometimes, my code works. Sometimes, it doesn't.
I find it quite difficult to make sure it works in all sort of different ways. Unless it is just a helper predicate for myself, you never really know what your users want to test it with. Sometimes the problem can even be ill defined, it is unclear what should my_length(L, 5) outputs, for example.
Are there any best practices for that?
For practical programming, I found it much easier to just ignore these other ways and focus on only a particular way of calling. That's how I get things done, I am just worried about the possibility that someone else call it in a different way.
Is there a way for me to make that restriction at the language level? Or should I?
In particular, I am trying to write my_length such that it works for
Specifying list, calculating length, and
Specifying length, give me back a list that has length unbounded slot.
my_length([], 0).
my_length([_|T], A) :- my_length(T, TA), A is TA + 1.
That works fine both ways, except it prompts for more answers when I ask the reverse question, and then we get a stack overflow. We also can't do arithmetic with the length argument since it could be unspecified.
This is just a specific case.
Can use cut (i.e. the exclamation mark):
list_length(Lst, Len) :-
nonvar(Len),
% Commit to this path
!,
% Using an accumulator - faster than recursion
list_length_(Lst, 0, Len),
% No more than 1 solution
!.
list_length(Lst, Len) :-
list_length_(Lst, 0, Len).
% Found end of list
list_length_([], Len, Len).
list_length_([_|T], Upto, Len) :-
% Iterate through list
inc_below_max(Upto, Len, Upto1),
list_length_(T, Upto1, Len).
% Increment, keeping to maximum (if specified)
inc_below_max(I, Max, I1) :-
I1 is I + 1,
( nonvar(Max)
-> I1 =< Max
; true
).
Results in swi-prolog:
?- list_length([a,b,c], Len).
Len = 3.
?- list_length(Lst, 3).
Lst = [_, _, _].
?- Lst = [a,b,c], list_length(Lst, Len).
Len = 3.
?- Lst = [a,b|Tail], list_length(Lst, 1).
false.
This avoids unwanted choicepoints.
So I am an absolute beginner in Prolog. I am learning recursion at the moment and this is what I got until now on my task.
dance(start).
dance(forward(T)) :- dance(T).
dance(backward(T)) :- dance(T).
count(start,0,0).
count(forward(X),succ(Y),Z) :- count(X,Y,Z).
count(backward(X),Y,succ(Z)) :- count(X,Y,Z).
greater(succ(0),0).
greater(succ(Y),succ(Z)):-greater(Y,Z).`
Summary of what this is supposed to do: There can be dances starting with the "start" and then either forward or backward addition per recursion. In count, I managed to be able to count the amount of forward and backward in a given sequence and save them in the "succ" notation and in greater I want to compare two of such "succ" numbers. And greater shall be true if the first argument is larger (consists of more "succs" than the second argument.
Now my task is to write a new rule "more(X)" which is true if the sequence X (build from dance) has more forward than backward in it. I think I have all the subtasks I need for it but now I am helpless with chaining them together because until now I only had 2 rules with the same amount of parameters but in this case, I got one with one, two, and three parameters. The solution should be something like this
more(X):-greater(Y,Z)
but how do I get my "succ" umbers from "count" to "greater" and the given sequence X to "count"? I do have to change some of the rules otherwise count is never called, right?
So it should be more like more(X):-greater(count(X,Y,Z)) ?
But like this, I would have to change the greater rules to be able to "get" this type of parameter.
Example query ?- more(backward(forward(start))).
false.
?- more(forward(start)).
true.
Your dance/1 and count/3 predicates seems correct.
If you want "greater" where greater(X, Y) means that X is greater than Y, you'd write:
greater(succ(_), 0).
greater(succ(X), succ(Y)) :- greater(X, Y).
Your solution checks if X is exactly one greater than Y.
Note that nothing is greater than 0.
If you implement more/1 in terms of count/3 and greater/2, you'd write:
more(X) :-
count(X, Forward, Backward),
greater(Forward, Backward).
So it should be more like more(X):-greater(count(X,Y,Z)) ?
No, you are writing that as if it is Python and greater(count(X,Y,Z)) will call greater(...) on the return from count. Prolog predicates are not function calls, and count(...) does not return anything in that way.
The result of the count is Y and Z. (These names you are using could be clearer). Do the count, and then after, use the Y and Z for something else.
count(X,Y,Z),
greater(Y,Z)
The comma being AND; "this code works if count of X is Y and Z AND Y is greater than Z".
I am trying to find the sum of a list in Prolog. Below is the total/sum code. It's close to working, however it returns the factors of the sum instead of just the sum. New to Prolog so I am not sure why this is happening.
sum([], 0).
sum([X|Tail],Sum):-
sum(Tail,Temp),
Sum=Temp+X.
Why does this result in the factors of the total being shown instead of the actual total value? The values add up to the correct answer, just not sure why it is displayed like this.
Input/Output:
Total = 0+3000.0+1900.0+1312.5+3000+1900+5000 ?
You're using term unification (=/2) instead of arithmetic evaluation (is/2) in the totalList/2 predicate:
totalList([], 0).
totalList([X|Tail],Total):-
totalList(Tail,Temp),
Total=Temp+X.
Rewrite as:
total_list([], 0).
total_list([X| Tail], Total):-
total_list(Tail, Temp),
Total is Temp + X.
The rename from totalList to total_list follows Prolog coding guidelines for predicate names.
Although not a bug, the performance of your predicate also suffers from not being tail-recursive. I.e. the recursive call in the second clauses is not the last goal in its body. Therefore, it will consume space proportional to the number of elements in the list. You can fix this problem by using an accumulator:
total_list(List, Sum) :-
total_list(List, 0, Sum).
total_list([], Sum, Sum).
total_list([X| Tail], Sum0, Sum):-
Sum1 is Sum0 + X,
total_list(Tail, Sum1, Sum).
This improved definition will run in constant space in most Prolog systems.
I need to find the least multiple of N in a list of numbers.
leastMultiple/2
leastMultipleOfThree/2,
arg1= list of numbers,arg2= X (X is what we want to find, the least multiple of 3 in a list of numbers).
For example, find the least multiple of 3 in [7,9,15,22]. I have been staring at this for quite some time, and I'm not entirely sure where to begin. If you can simply help me wrap my head around the problem a bit, I'd be very thankful.
An earlier version of my answer was confused by the use of the word "least multiple." You want to find the multiples in the list, and retrieve the smallest. I understand now.
First we must detect a multiple of N. We can do this by dividing and looking at the remainder using the modulo operator, like this:
?- X is 7 mod 3.
X = 1.
?- X is 9 mod 3.
X = 0.
I will define a convenience method for this, is_multiple_of:
% multiple_of(X, N) is true if X is a multiple of N
multiple_of(X, N) :- 0 is X mod N.
Now we can simply say:
?- multiple_of(7, 3).
false.
?- multiple_of(9, 3).
true.
Now there are two ways to proceed. The efficient approach, which could easily be made tail recursive for greater performance, would be to walk the list once with an accumulator to hold the current minimum value. A less code-intensive approach would be to just filter the list down to all multiples and sort it. Let's look at both approaches:
% less code: using setof/3
leastMultipleOfThree(List, Result) :-
setof(X, (member(X, List), multiple_of(X, 3)), [Result|_]).
setof/3 evaluates its second term as many times as possible, each time retrieving the variable in its first term for inclusion in the result, the third term. In order to make the list unique, setof/3 sorts the result, so it happens that the smallest value will wind up in the first position. We're using member(X, List), multiple_of(X, 3) as a very simple generate-test pattern. So it's terse, but it doesn't read very well, and there are costs associated with building lists and sorting that mean it isn't optimal. But it is terse!
% more code: using an accumulator
leastMultipleOfThree(List, Result) :- leastMultipleOfThree(List, null, Result).
% helper
leastMultipleOfThree([], Result, Result) :- Result \= null.
leastMultipleOfThree([X|Xs], C, Result) :-
multiple_of(X, 3)
-> (C = null -> leastMultipleOfThree(Xs, X, Result)
; (Min is min(X, C),
leastMultipleOfThree(Xs, Min, Result)))
; leastMultipleOfThree(Xs, C, Result).
This is quite a bit more code, because there are several cases to be considered. The first rule is the base case where the list is extinguished; I chose null arbitrarily to represent the case where we haven't yet seen a multiple of three. The test on the right side ensures that we fail if the list is empty and we never found a multiple of three.
The second rule actually handles three cases. Normally I would break these out into separate predicates, but there would be a lot of repetition. It would look something like this:
leastMultipleOfThree([X|Xs], null, Result) :-
multiple_of(X, 3),
leastMultipleOfThree(Xs, X, Result).
leastMultipleOfThree([X|Xs], C, Result) :-
multiple_of(X, 3),
C \= null,
Min is min(X, C),
leastMultipleOfThree(Xs, Min, Result).
leastMultipleOfThree([X|Xs], C, Result) :-
\+ multiple_of(X, 3),
leastMultipleOfThree(Xs, C, Result).
This may or may not be more readable (I prefer it) but it certainly performs worse, because each of these rules creates a choice point that if/else conditional expressions within a rule do not. It would be tempting to use cuts to improve that, but you'll certainly wind up in a hellish labyrinth if you try it.
I hope it's fairly self-explanatory at this point. :)
I am trying to do a small project in prolog where a user can input a list and then it calculates the average, max in the list etc. etc.
So far so good, but I ran into a problem when writing the max function (finds max number in the list). The code is:
maxN([X],X):-!.
maxN([X|L],X) :- maxN(L,M), X > M.
maxN([X|L],M) :- maxN(L,M), M >= X.
The function itself works separately, but I get this error message:
The predicate 'forma::maxN/2 (i,o)', which is declared as 'procedure', is actually 'nondeterm' forma.pro
This is my predicate in the *.cl definition:
maxN: (integer* Z, integer U) procedure (i,o).
I cannot declare it as nondeterm because it causes issues with my whole form. Can you help me/give a hint how to make it a procedure? I am thinking I have to make a cut somewhere but my attempts have failed so far.
P.S. I am using Visual Prolog 7.4.
Edit: After trying the alternatives proposed to make the two rules into one or with an accumulator, I now get that the predicate is 'determ' instead of a procedure. According to my Prolog guide that means that the predicate doesn't have multiple solutions now, but instead has a chance to fail. Basically all code variations I've done up to now lead me to a 'determ'.
The problem is that Prolog sees a choice point between your second and third rules. In other words, you, the human, know that both X > M and M >= X cannot both be true, but Prolog is not able to infer that.
IMO the best thing to do would be to rephrase those two rules with one rule:
maxN([X], X) :- !.
maxN([X|L], Max) :-
maxN(L, M),
X > M -> Max = X
; Max = M.
This way there isn't ever an extra choice point that would need to be pruned with a cut.
Following #CapelliC's advice, you could also reformulate this with an accumulator:
maxN([X|Xs], Max) :- maxN_loop(Xs, X, Max).
maxN_loop([], Max, Max).
maxN_loop([X|Xs], Y, Max) :-
X > Y -> maxN_loop(Xs, X, Max)
; maxN_loop(Xs, Y, Max).
sorry, I don't know the Prolog dialect you're using, my advice is to try to add a cut after the second clause:
maxN([X|L],X) :- maxN(L,M), X > M, !.
Generally, I think a recursive procedure can be made deterministic transforming it to tail recursive. Unfortunately, this requires to add an accumulator:
maxN([],A,A).
maxN([X|L],A,M) :- X > A, !, maxN(L,X,M).
maxN([X|L],A,M) :- maxN(L,A,M).
Of course, top level call should become
maxN([F|L],M) :- maxN(L,F,M).