Related
I'm studying Prolog, in particular I'm focused on list.
Given a number n, return a list of numbers from 0 to n.
As example, given 2 the output will be [0,1,2]
Here is my code:
num2list(0,[0]).
num2list(X,[H|T]) :-
H is X,
N is X-1,
num2list(N,T).
the output for num2list(2,X) is X=[2,1,0].
Maybe the solution is stupid, but I can't find a way. I tried to make some modifications to my code, but I just get errors.
This program is mine and I don't want use standard predicates like "in" or something , because I don't know and I want to make a pure recursion.
So what is an easy way to do this?
I see it done this way in a book, and I want maintain this way.
You want a list with ascending order but the predicate definition is constructing it in descending order. There's more than one sensible solution for this problem, including using de facto standard predicates such as between/3. A solution close to the one you're trying is to use an additional argument:
num2list(N, List) :-
num2list(0, N, List).
num2list(N, N, [N]).
num2list(N0, N, [N0| List]) :-
N0 < N,
N1 is N0 + 1,
num2list(N1, N, List).
Sample call:
?- num2list(2, L).
L = [0, 1, 2] ;
false.
An issue of this particular solution is the spurious choice-point as you can notice on the sample call. This issue is also present in your code. It can be easily solved with a less declarative solution by using a cut or an if-then-else construct.
A simple solution:
num2list(N,L):-findall(X,between(0,N,X),L).
findall puts all Xs that satisfy the between to the list L.
I have a list of terms as below
[t('L', 76), t('I', 73), t('V', 86), t('E', 69)]
I want to write a predicate in prolog so that it will return the term with minimum second value. i.e. from above list it should return t('E', 69)
Below is what I tried. But this is not working.
minChar(L, Min) :-
setof(t(_, A), member(t(_, A), L), Li),
Li = [Min|_].
Here is the output it gives for above input.
?- minChar([t('L', 76), t('I', 73), t('V', 86), t('E', 69)], Min).
Min = t(_G14650, 69) ;
Min = t(_G14672, 73) ;
Min = t(_G14683, 76) ;
Min = t(_G14661, 86).
As lurker says, predicates can't start with a capital letter, so fix that first.
There are two basic problems here: first off all, the two underscores in your second line refers to different variables, so setof/3 doesn't know that you want the same variable both in the template and in the member/2 call.
Second, setof sorts the result (which is why you can extract the minimum like that), but the way you've constructed the template, it will sort it incorrectly. Sorting in swi-prolog uses the standard order of terms definition, and in your case, you're sorting compound terms of the type t(A, B), where A is an atom and B is a number. This will sort it lexicographically first on A and then on B, which is not what you want, you want to sort on B.
The standard trick here when you want to sort things with a key that isn't identical to the term itself is to extract the key you want, bind it with the (-)/2 functor, and then sort it. So, for your example, this should work:
minChar(L, Min) :-
setof(B-t(A, B), member(t(A, B), L), Li),
Li = [_-Min|_].
Remember here that in Prolog, when you say X - Y, you're not actually doing any subtraction, even though it looks you are. You are simply binding X and Y together using the (-)/2 functor. It only does subtraction if you specifically ask it to, but using some operator that forces arithmetic evaluation (such as =:=, <, > or is, for instance). This is why 1+1 = 2 is false in Prolog, because = is a unification operator, and doesn't do any arithmetic evaluation.
To be clear: you don't have to use - for this, you can use whatever functor you like. But it's traditional to use the minus functor for this kind of thing.
Edit: also, setof/3 will backtrack over any free variables not found in the template, and since the two underscores don't refer to the same free variables, it will backtrack over every possible assignment for the second underscore, and then throw that result away and assign a new free variable for the first underscore. That's why you can backtrack over the result and get a bunch of anonymous variables that you don't know where they came from.
Instead of using a setof which runs in O(n log n) (at least), you can also write a minChar predicate yourself:
minChar([X],X) :-
!.
minChar([t(_,V1)|T],t(A2,V2)) :-
minChar(T,t(A2,V2)),
V2 < V1,
!.
minChar([X|_],X).
Or you could further boost performance, by using an accumulator:
minChar([X|T],Min) :-
minChar(T,X,Min).
minChar([],X,X).
minChar([t(A2,V2)|T],t(_,V1),Min) :-
V2 < V1,
!,
minChar(T,t(A2,V2),Min).
minChar([_|T],X,Min) :-
minChar(T,X,Min).
The code works as follows: first you unify the list as [X|T], (evidently there must be at least one items, otherwise there is no minimum). Now you take X as the first minimum. You iterate over the list, and at each time you compare t(A2,V2) (the new head of the list), with t(A1,V1) (the currently found minimum). If the second attribute V2 is less than V1, we know we have found a new minimum, and we continue our search with that term. Otherwise, the quest is continued with the old current minimum. If we reach the end of the list, we simply return the current minimum.
Another performance hack, is placing the empty list case as the last one, and place the the current minimum is the smallest case first:
minChar([t(_,V2)|T],t(A1,V1),Min) :-
V1 <= V2,
!,
minChar(T,t(A1,V1),Min).
minChar([X|T],_,Min) :-
minChar(T,X,Min).
minChar([],X,X).
This because Prolog always first executes the predicates in the order defined. It will occur only once that you reach the empty list case (at the end of the list). And after a will, the odds of finding a smaller value will be reduced significantly.
You are a beginner in Prolog, so try to think Prolog.
What is the minimum of a list ? An element of this list, and no other element of this list is smaller.
So you can write
my_min(L, Min) :-
member(Min, L),
\+((member(X, L), X < Min)).
One will say : "it's not efficient !". Yes, but I think it's a good way to learn Prolog.
You should adapt this code to your case.
EDIT I said adapt :
min_of_list(L, t(X,Y)) :-
member(t(X, Y), L),
\+((member(t(_, Z), L), Z < Y)).
I am trying to get a feel for Prolog programming by going through Ulle Endriss' lecture notes. When my solution to an exercise does not behave as expected, I find it difficult to give a good explanation. I think this has to do with my shaky understanding of the way Prolog evaluates expressions.
Exercise 2.6 on page 20 calls for a recursive implementation of a predicate last1 which behaves like the built-in predicate last. My attempt is as follows:
last1([_ | Rest], Last) :- last1(Rest, Last).
last1([Last], Last).
It gives the correct answer, but for lists with more than one element, I have to key in the semicolon to terminate the query. This makes last1 different from the built-in last.
?- last1([1], Last).
Last = 1.
?- last1([1, 2], Last).
Last = 2 ;
false.
If I switch the order in which I declared the rule and fact, then I need to key in the semicolon in both cases.
I think I know why Prolog thinks that last1 may have one more solution (thus the semicolon). I imagine it follows the evaluation sequence
last1([1, 2], Last).
==> last1([2], Last).
==> last1([], Last). OR Last = 2.
==> false OR Last = 2.
That seems to suggest that I should look for a way to avoid matching Rest with []. Regardless, I have no explanation why switching the order of declaration ought to have any effect at all.
Question 1: What is the correct explanation for the behavior of last1?
Question 2: How can I implement a predicate last1 which is indistinguishable from the built-in last?
Question 1:
Prolog systems are not always able to decide whether or not a clause will apply prior to executing it. The precise circumstances are implementation dependent. That is, you cannot rely on that decision in general. Systems do improve here from release to release. Consider as the simplest case:
?- X = 1 ; 1 = 2.
X = 1
; false.
A very clever Prolog could detect that 1 = 2 always fails, and thus simply answer X = 1. instead. On the other hand, such "cleverness" is very costly to implement and time is better spent for optimizing more frequent cases.
So why do Prologs show this at all? The primary reason is to avoid asking meekly for another answer, if Prolog already knows that there is no further answer. So prior to this improvement, you were prompted for another answer for all queries containing variables and got the false or "no" on each and every query with exactly one answer. This used to be so cumbersome that many programmers never asked for the next answer and thus were not alerted about unintended answers.
And the secondary reason is to keep you aware of the limitations of the implementation: If Prolog asks for another answer on this general query, this means that it still uses some space which might accumulate and eat up all your computing resources.
In your example with last1/2 you encounter such a case. And you already did something very smart, BTW: You tried to minimize the query to see the first occurrence of the unexpected behavior.
In your example query last1([1,2],X) the Prolog system does not look at the entire list [1,2] but only looks at the principal functor. So for the Prolog system the query looks the same as last1([_|_],X) when it decides which clauses to apply. This goal now fits to both clauses, and this is the reason why Prolog will remember the second clause as an alternative to try out.
But, think of it: This choice is now possible for all elements but the last! Which means that you pay some memory for each element! You can actually observe this by using a very long list. This I get on my tiny 32-bit laptop — you might need to add another zero or two on a larger system:
?- length(L,10000000), last1(L,E).
resource_error(_). % ERROR: Out of local stack
On the other hand, the predefined last/2 works smoothly:
?- length(L,10000000), last(L,E).
L = [_A,_B,_C,_D,_E,_F,_G,_H,_I|...].
In fact, it uses constant space!
There are now two ways out of this:
Try to optimize your definition. Yes, you can do this, but you need to be very smart! The definition by #back_dragon for example is incorrect. It often happens that beginners try to optimize a program when in fact they are destroying its semantics.
Ask yourself if you are actually defining the same predicate as last/2. In fact, you're not.
Question 2:
Consider:
?- last(Xs, X).
Xs = [X]
; Xs = [_A,X]
; Xs = [_A,_B,X]
; Xs = [_A,_B,_C,X]
; Xs = [_A,_B,_C,_D,X]
; ... .
and
?- last1(Xs, X).
loops.
So your definition differs in this case with SWI's definition. Exchange the order of the clauses.
?- length(L,10000000), last2(L,E).
L = [_A,_B,_C,_D,_E,_F,_G,_H,_I|...]
; false.
Again, this false! But this time, the big list works. And this time, the minimal query is:
?- last2([1],E).
E = 1
; false.
And the situation is quite similar: Again, Prolog will look at the query in the same way as last2([_|_],E) and will conclude that both clauses apply. At least, we now have constant overhead instead of linear overhead.
There are several ways to overcome this overhead in a clean fashion - but they all very much depend on the innards of an implementation.
SWI-Prolog attempts to avoid prompting for more solutions when it can determine that there are none. I think that the interpreter inspect the memory looking for some choice point left, and if it can't find any, simply state the termination. Otherwise it waits to let user choice the move.
I would attempt to make last1 deterministic in this way:
last1([_,H|Rest], Last) :- !, last1([H|Rest], Last).
last1([Last], Last).
but I don't think it's indistinguishable from last. Lurking at the source code of the library (it's simple as ?- edit(last).)
%% last(?List, ?Last)
%
% Succeeds when Last is the last element of List. This
% predicate is =semidet= if List is a list and =multi= if List is
% a partial list.
%
% #compat There is no de-facto standard for the argument order of
% last/2. Be careful when porting code or use
% append(_, [Last], List) as a portable alternative.
last([X|Xs], Last) :-
last_(Xs, X, Last).
last_([], Last, Last).
last_([X|Xs], _, Last) :-
last_(Xs, X, Last).
we can appreciate a well thought implementation.
this code would work:
last1([Last], Last).
last1([_ | Rest], Last) :- last1(Rest, Last), !.
it is because prolog things there might be more combinations but, with this symbol: !, prolog won't go back after reaching this point
I have this code for splitting input list into its halves. It seems to be OK.
halve(List,A,B) :- halve(List,List,A,B), !.
halve(B,[],[],B).
halve(B,[_],[],B).
halve([H|T],[_,_|T2],[H|A],B) :-halve(T,T2,A,B).
Ok, so I tried to decode it. The beginning is clear:
"Halve took list and 2 logic variables" is this:
halve(List,A,B)
(1) Then continuous this part:
:- halve(List,List,A,B).
And this means, that I am creating new two lists (List, List) from the first one or what? What exacly represents ":-"? I guess the new lists = halves will be the A, and B, right?
(2) Second, please, I don't quite get these two lines:
halve(B,[],[],B).
halve(B,[_],[],B).
Maybe you could explain it on some examples, please?
(3) Well, I hope after your explanation of (1) and (2), I'll get the final part by myself...
halve([H|T],[_,_|T2],[H|A],B) :- halve(T,T2,A,B).
Thank you very, very much for helping me.
Ok, our first problem already has its solution. Long story short, it works like this:
halve([1,2,3,4,5],[1,2],[3,4,5]).
->true
If you notice it splits the list into its halves but if the list has an odd number of the elements, the second half is the bigger one.
Now what I want to obtain is to have the first one bigger.
So I'm thinking about this:
I'm going to reach this:
Halves_div([1,2,3],A,B).
A=[1,2],
B=[3].
Let's say my input is list: [1,2,3]. So I'll start with splitting list's head and tail: [H|T] and then I will merge the H with new empty list - my 1st Half (A).
After that I have A=[1], B=[] and Input=[2,3].
For merging I have:
merge([],List,List).
merge([H|T],List,[H|New]) :- merge(T,List,New).
And one more thing - I need to check whether the 1st half is already >= 2nd half, right?
So this is my idea and only thing I'd love you to help me is to write it in prolog. I'm kinda confused how to put it together.
Thanks!
It seems my idea of solution is too complicated and I found something better!
To start, a Prolog clause looks like that:
Head :- Body
You can read that as "Head if Body", or "Body implies Head".
Note that sometimes you just have
Head
That's because Head is always true. Instead of calling Head a clause, we rather call it a fact in this case.
So here, we have:
halve(List,A,B) :- halve(List,List,A,B).
That means that halve(List, A, B) is true if halve(List, List, A, B) is true. Concretely it's just a way to delegate the work of halve/3 to halve/4, a so called worker predicate.
Why do we need a worker predicate? Well, because here we'd like to use another variable to calculate our A and B terms. But we couldn't do that with halve/3 because the 3 argument spots of halve/3 were already taken by the input list, List, the first half of the result, A and the second half of the result, B.
About the List, List thing, it's just a way to say that we call halve/4 with the same first and second argument, like you would in any programming language.
Then the interesting stuff starts. Prolog will try to prove that halve/4 is true for some given arguments. Let's say to illustrate the execution that we called halve/3 this way:
?- halve([1, 2], A, B).
Then, if you followed what I talked about previously, Prolog will now try to prove that halve/3 is true by proving that halve/4 is true with the following arguments: halve([1, 2], [1, 2], A, B)..
To do that, Prolog has 3 choices. The first choice is the following clause:
halve(B,[],[],B).
Obviously, that won't work. Because when Prolog will try to fit the second argument of the caller "in" the second argument of the callee through unification, it will fail. Because
[1, 2] can't be unified with [].
Only two choices left, the next is:
halve(B,[_],[],B).
Same thing here, Prolog cannot unify [1, 2] and [_] because _ is just a variable (see my post about the anonymous variable _ if you've troubles with it).
So the only chance Prolog has to find a solution to the problem you presented it is the last clause, that is:
halve([H|T],[_,_|T2],[H|A],B) :- halve(T,T2,A,B).
Here, Prolog will find a way to unify thing, let's see which way:
we have to unify [1, 2] with [H|T]. That means that H = 1. and T = [2].
we have to unify [1, 2] with [_,_|T2]. that means that T2 = [].
now we start to build our results with the next unification, ie A = [H|A'] (I primed the second A because variables are scoped locally and they are not the same). Here we tell that when we'll have our result calculated from the body of the clause, we'll add H to it. Here H is 1 so we already know that the first element of A will be 1.
Ok ok, unification succeeded, great! We can proceed to the body of the clause. It just calls halve/4 in a recursive manner with those values (calculated above):
halve([2], [], A, B).
And here we start all over again. Though this time things will be fast since the first choice Prolog has will be a good fit:
halve(B,[],[],B).
can be unified to
halve([2], [], A, B).
with those values: A = [] and B = [2].
So that's a good step, we now reached the "base case" of the recursion. We just have to build our result from bottom to top now. Remember when we called recursively our predicate halve/4 a few steps above? We had already said that the first element of A would be 1. Now we know that the tail is [] so we can state that A = [1]. We hadn't stated anything particular about B so B = [2] is left untouched as the result.
Now that I detailed the execution, you might wonder, why does this work? Well, if you pay attention, you'll note that the second argument of halve/4 is gone through twice as fast as the first one. [H|T] vs [_, _|T2]. That means that when we hit the end of the list with our second argument, the first one is still at the middle of our list. This way we can divide the thing in two parts.
I hope I helped you catch some of the subtle things at work here.
halve(List,A,B) copies first half of List to A and unifies second half with B
That will be true when length of our list will be even: halve(B,[],[],B).
That will be true when length of out list will be odd: halve(B,[_],[],B).
halve([H|T],[_,_|T2],[H|A],B) :- halve(T,T2,A,B).
Here we are setting 2 lets call them 'pointers' in each step we copy one element from beginning of our list to A because we want get first half.
Because in each step we are removing 2 elements from our list [_,_|T2] Predicate will stop when list will have only one left element or empty, then it will unify rest of our list with B. If you cant understand use trace/0
This version might prove useful ...
split_in_half(Xs, Ys, Zs) :- length(Xs, Len),
Half is Len // 2, % // denotes integer division, rounding down
split_at(Xs, Half, Ys, Zs).
split_at(Xs, N, Ys, Zs) :- length(Ys, N), append(Ys, Zs, Xs).
so i have a homework question that asks me to find the third element of a list, as well as the last element of a list and print them out (2 separate programs).
I Thought my Code would work to find the third element, by keeping track of a index, but i recieve a error when i try to run the code:
findthird([], Result).
findthird(List, Result) :- secondFunc(List, 0, Result).
secondFunc([Head|Tail], Count, Result) :-
Count < 3, Count is Count+1, secondFunc(Tail, Count, Result).
secondFunc([Head|Tail], Count, [Head|Result]).
Have any ideas for this?
The output i receieve now Is :
| ?- findthird([2,3,4], Result).
Result = [2|_]
yes
I am still having a tough time wrapping my head around Prolog, i just cant seem to understand it.
Any help is appreciated as always,
Thank.
Updated with new attempt code***
Updated ** This is the code that solved my problem:
findthird([], Result).
findthird(List, Result) :- secondFunc(List, 0, Result).
secondFunc([], Count, []).
secondFunc([Head|Tail], Count, Result) :-
Count1 is Count+1, Count1 < 3, secondFunc(Tail, Count1, Result).
secondFunc([Head|Tail], Count, Head).
Input:
| ?- findthird([3,4,5], Result).
Output:
Result = 5 ?
yes
Input:
| ?- findthird([3,4,5,6,7], Result).
Output:
Result = 5 ?
yes
First of all, you have to understand that in Prolog, you don't manipulate return values of function. The reason behind this is that you do not manipulate functions, but predicates. So length(List) never evaluates to a number, but to true or false, as any other predicate. When you write findelement(List, length(List), len... the findelement predicate won't be called with something like [a, b, c] and 3, it will be called with something like [a, b, c] and length([a, b, c]). So already your program cannot work.
That put aside, your program is still very wrong. The basic way a recursion works in prolog or in functional languages (as well as when you use structural induction in maths) is as follows :
a clause for initialization
a clause for heredity
In your program, you don't have an initialization clause. Meaning that when recursion hits [], no clause can handle it, and the thing fails. The rest is false too, but I think it's especially important to get the recursion principles right first.
To illustrate that without spoiling the problem for you (it's homework after all), I'll take an example : say you wanna test if a sheepfold is safe. The sheepfold is safe if there's no wolf in it. If we represent the sheepfold by a list and the wolf by the atom wolf, we can write the predicate like that :
Initialization : if the sheepfold is empty, it's safe, there's no wolf in it.
safe_sheepfold([]).
Heredity : if the sheepfold is safe with n-1 members, it's safe with n members if the added member is not a wolf :
safe_sheepfold([Animal|Sheepfold]) :-
Animal =\= wolf,
safe_sheepfold(Sheepfold).
And that's it. To see how prolog handles the request, compile this and issue a trace. command before running the predicate, as pointed out in your last question, it will help you to understand how things work.
To let you think about that with a more concrete example, here is a classic predicate, factorial (it uses arithmetic too) :
Here is our initialization clause :
factorial(0, 1).
Here is our heredity clause :
factorial(N, F) :-
N > 0,
NextN is N - 1,
factorial(NextN, NextF),
F is NextF * N.
To keep this simple I didn't make this predicate tail recursive nor used cuts, you'll learn about those things later on!
I hope my rambling will be of some help.
edit post update :
It's almost that ! Now just a few more hints : the result you want is not a list, it's just an element, so try to modify the last clause to just return the element, not a list with the element. And the initialization clause is actually your last clause here (the thing that checks if you're above 3), so you don't need the one with [] ! You're almost there :)