I was trying to create a predicate that concatenates two lists in such a way that
test([1,2], [3,4], X) would give X = [1,3,2,4].
My attempt looks like that
test([], [], _).
test([X|L1], [Y|L2], L3) :-
append([X, Y], L3, L4),
test(L1, L2, L4).
The thing is, it only gives true. output, so it seems like my list at the end doesn't get stored under L3 var? I'm not quiet sure how to go around that, I would appreciate any tips.
What you have is a good start and nearly functional. Here are a few comments.
The name test is quite generic and a better name should be used. This is not only a good practice from a readability standpoint, but generic names can often collide with predefined system predicates. In this case, I would choose interleave or zip which are common names for this relationship between two lists.
Your base case test([], [], _) effectively says that the result of operating on two empty lists is any list you want, which clearly isn't logical. It should be interleave([], [], []).
The use of append/3 in append([X,Y], L3, L4) is overkill. You can simply write: L4 = [X,Y|L3], or even more compactly:
interleave([X|L1], [Y|L2], [X,Y|L3]) :-
interleave(L1, L2, L3).
With that single base case, you limit the successful solutions to only include two lists of the same length. If you wish lists of different length, you'd want some additional logic to accommodate. This can be done with just two base cases. Putting it all together, you'd have:
interleave([], L, L). % interleaving the empty list with any list is the same list
interleave([H|T], [], [H|T]). % interleaving any non empty list
% with the empty list is the same list
interleave([X|L1], [Y|L2], [X,Y|L3]) :-
interleave(L1, L2, L3).
Related
I have to make a predicate reverseeven(List, Reversed), that will reverse a list ONLY if the list has an even number of elements, and will return the empty list if it does not.
I have a function that determines whether the list has an even number of elements and a reverse function:
evenlength([_,_]).
evenlength([_,_|X]):-
evenlength(X).
reverse([_,_],R).
reverse([H|T], R):-
reverse(T,ReverseT), append(ReverseT, [H], R).
But I'm unsure of how to combine the two.
You can't "combine" predicates, but you can have a logical conjunction between two (or more) predicates which will succeed only if both of them succeed:
reverseEven(List, Reversed) :-
evenlength(List), % This must succeed
reverse(List, Reversed). % and this one in order this case to succeed
reverseEven(_, []). % this will succeed otherwise
The above is not the most efficient implementation (you can utilize the cut ! operator after the check for the even length for example). But it shows the idea.
Update
By the way, your reverse predicate should look like this:
reverse([],[]). % Empty list is a reverse of empty list
reverse([H|T], R):-
reverse(T,ReverseT), append(ReverseT, [H], R).
Update 2 Thanks #Lurker. The above code will produce two answers. The first one will be correct. If we ask Prolog to search further it will find another answer which is empty list, as the second clause is always true. In order to solve this, we can explicitly check that the length of the list is not even using the negation operator, or what I find more elegant is just to add another clause for the empty list, and for the non-even checking just use the existing evenlength with the list with extra element:
reverseEven([], []).
reverseEven(List, Reversed) :-
evenlength(List), % This must succeed
reverse(List, Reversed). % and this one in order this case to succeed
reverseEven([H|T], []) :-
evenlength([H|[H|T]]).
I have this issue in Prolog where I'm creating a list, and sometimes predicates that contribute to this list creation return an empty list, []. In the end I end up with a list that looks like [[1, 2, 3], []] for example, when I'd rather it be [[1, 2, 3]].
How do I stop that empty list when I return it from being put with the rest of the list? My logic programming isn't terrible strong, but in other languages I'd simply say, if not empty: append, otherwise don't do anything.
Is this possible in Prolog?
EDIT: To put it in an example, say I have the following predicate:
put_together(Value1, Value2, Result) :-
Result = [Value1, Value2].
I call put_together(1, 2, Result). and get Result = [1, 2] as expected. But if I call, put_together(1, [], Result). I get Result = [1, []] which I don't want, I'd rather have the final empty list gone, which would be simply [1].
DCGs are often a good way to describe lists in Prolog. This makes reasoning about lists a lot easier. You should try it in your use case.
For example, to "put together" (see below for why this is not a good view of the matter) two lists, as you say it, you can use:
lists_together(Ls1, Ls2) -->
list(Ls1),
list(Ls2).
list([]) --> [].
list([L|Ls]) --> [L], list(Ls).
Sample cases:
?- phrase(lists_together([a,b,c], [d,e]), Ts).
Ts = [a, b, c, d, e].
?- phrase(lists_together([a,b,c], []), Ts).
Ts = [a, b, c].
This is completely general and works in all directions. Try for example the most general query, or iterative deepening etc. I therefore avoid an imperative name like put_..., which would indicate that it works only in one direction. Instead, I use a more declarative name that does justice to the multiple directions in which this relation holds.
However, in your case, it seems that you are somehow, and involuntarily, mixing terms of different kinds. To denote pairs, do not use [A,B] (which is .(A, .(B, []))), but rather use terms like A-B.
So, to relate such pairs to their components, use for example:
key_value_pair(Key, Value, Key-Value).
If possible, I'd recommend changing your predicates so that you always return lists of lists, and always compose them with append/3. That way, you can absorb empty lists as-if they were zeros in a sum and stop worrying about empty lists being corner cases.
DCG's, as mention in mat's answer, are a possible way to consistently use lists.
I need a query, which will remove me all variables and duplicates from list.
Example:
?- L = [1,2,3,X,Y,3,2], my_awesome_predicate(L, Res).
Then, Res should be: [1,2,3].
I don't care about order (it could be [2,3,1], [3,2,1] or whatever).
Unfortunately, I have a task in which I have to care about efficiency, so my main question is - can it be done faster? Currently, I have the following code:
remove_variables([], []).
remove_variables([H|List], Res):- var(H), !, remove_variables(List, Res).
remove_variables([H|List], [H|Res]):- remove_variables(List, Res).
my_awesome_predicate([], []).
my_awesome_predicate(List, Res):-
sort(List, Sorted),
remove_variables(Sorted, Res).
If you are using SWI then you can improve a little further with this code:
my_awesome_predicate(List, Res):-
sort(List, MRes),
remove_variables(MRes, Res).
remove_variables([Var|Tail], NTail):-
var(Var),
!,
remove_variables(Tail, NTail).
remove_variables(Res, Res).
as it seems that SWI's sort will leave unbounded variables first (don't know if this behavior is a standard among other prolog's), so you can stop removing variables once you find the first non-variable.
Reading a bit SWI's documentation, it's stated that:
4.7.1 Standard Order of Terms
Comparison and unification of arbitrary terms. Terms are ordered in
the so called ``standard order''. This order is defined as follows:
1. Variables < Numbers < Atoms < Strings < Compound Terms
so it seems safe to stop removing elements when you find the first non-variable...
awesome([],[]).
awesome([H|T],R):- var(H), !, awesome(T,R).
awesome([H|T],R):- awesome(T,[H],R).
awesome([],R,R).
awesome([H|T],A,R):- memberchk(H,A) -> awesome(T,A,R) ; awesome(T,[H|A],R).
Something like this? Theoretically it is quadratic, but your lists are very short and this code is very simple, so might get optimized by the compiler better.
If you append your resulting lists, better change it to work with difference lists, putting the output directly into the resulting list being built:
awesome([],Z,Z).
awesome([H|T],R,Z):- var(H), !, awesome(T,R,Z).
awesome([H|T],R,Z):- R=[H|Y], awesome(T,[H],Y,Z).
awesome([],_,Z,Z).
awesome([H|T],A,R,Z):- memberchk(H,A) -> awesome(T,A,R,Z)
; R=[H|Y], awesome(T,[H|A],Y,Z).
memberchk/2 of course weeds out variables as well as duplicates.
This is an old question but for the reference there is another nice and short solution using setof.
my_awesome_predicate(L, Res) :-
setof(X, (member(X, L), ground(X)), Res).
Res contains the solution without variables with the terms ordered by their first appearance.
?- my_awesome_predicate([1,2,3,X,Y,3,2], Res).
Res = [1, 2, 3].
Is it possible to define a list, that consists of predicates and how do I call the predicates.
Also, is it possible to pass one predicate to another predicate (like passing atoms)?
Example:
pre1:- something.
pre2(Predicate1, List):-
call(Predicate1),
append([Predicate1], List, R),
.....
You can't store predicates in a list, but you can store terms (or functors) and call terms as goals.
Here's a predicate that tests whether a term has the properties described by a list of functors:
has_properties([], _).
has_properties([P|Ps], X) :-
Goal =.. [P, X], % construct goal P(X)
call(Goal),
has_properties(Ps, X).
Usage:
% is 4 a number, an integer and a foo?
?- has_properties([number, integer, foo], 4).
The answer to this query will depend on your definition of foo/1, of course. See my explanation of =.. if needed.
Edit: as #false reports in the comments, it's not necessary to use =.., since Goal =.. [P, X], call(Goal) can be replaced by call(P, X) will have the same effect. It might still be worthwhile learning about =.., though, as you may encounter it in other people's code.
I've been given the question:
Define a predicate ordered/1, which checks if a list of integers is correctly in ascending order. For example, the goal ordered([1,3,7,11]) should succeed, as should the goal ordered([1,3,3,7]), whereas the goal ordered([1,7,3,9]) should fail.
So far I have this:
ordered([]).
ordered([N, M|Ns]):-
append(M, Ns, Tail),
ordered(Tail),
N =< M.
But it fails on every list.
I have deduced that the reason it fails is because it reaches the end number in the list then tries to compare that number against an empty list. Obviously this fails because you can't compare an integer to an empty list. Even if you could and it, say, returned 0 for an empty list, it would still return false as the number would be greater than 0, not less than.
I can't find a solution... Any ideas? Thanks, Jon.
Edit
So, some slightly amended code:
ordered([]).
ordered([N]):-
N >= 0.
ordered([N, M|Ns]):-
append(M, Ns, Tail),
ordered(Tail),
N =< M.
This now works for ordered([1]), but bigger lists still don't run correctly.
Should I include something like ordered([N, M|Ns]) in the definition?
(assuming this is homework, I hesitate to give a complete solution).
Looking at your code, try to find out how it would unify ?- ordered([1]).
Run this query mentally (or using trace/0) and see what it does, step by step, and how it computes its result.
Also, please try to get "returns a value" out of your mind when thinking prolog. Prolog predicates don't return anything.
I think your solution is not also tail-recursion-friendly.
Think something like that would do:
ordered([]) :-!.
ordered([_]):-!.
ordered([A,B|T]) :-
A =< B,
!,
ordered([B|T]).
If you are using SICStus Prolog,
my previous answer will not work, as the
clpfd library in SICStus Prolog
does not offer the library predicate
chain/3 included with
SWI-Prolog's clpfd library.
:- use_module(library(clpfd)).
:- assert(clpfd:full_answer).
Don't panic! Simply implement predicate ordered/1 like this:
ordered([]).
ordered([X|Xs]) :-
ordered_prev(Xs,X).
ordered_prev([] ,_ ).
ordered_prev([X1|Xs],X0) :-
X0 #=< X1,
ordered_prev(Xs,X1).
Let's see it in action with SICStus Prolog 4.3.2.
Here's the most general query:
?- ordered(Xs).
Xs = []
; Xs = [_A]
; Xs = [_A,_B], _A#=<_B, _A in inf..sup, _B in inf..sup
; Xs = [_A,_B,_C], _A#=<_B, _B#=<_C, _A in inf..sup, _B in inf..sup, _C in inf..sup
... % an infinity of solutions follows: omitted for the sake of brevity.
And here are the queries the OP suggested:
?- ordered([1,3,7,11]).
yes % succeeds deterministically
?- ordered([1,3,3,7]).
yes % succeeds deterministically
?- ordered([1,7,3,9]).
no
Note that both succeeding queries in above example did not leave any useless choicepoints behind, thanks to first argument indexing.
If your Prolog system supports clpfd, check if it offers the library predicate clpfd:chain/2.
:- use_module(library(clpfd)).
If so, simply write:
?- chain([1,3,7,11],#<).
true.
?- chain([1,3,3,7],#=<).
true.
?- chain([1,3,3,7],#<).
false.
?- chain([1,7,3,9],#<).
false.
You're quite right: according to your code there are only two possible ways a list can be ordered:
It's empty
The first two items are in the correct order, and the rest of the list is ordered
Those are certainly both correct statements, but what about the list [3]? Isn't that ordered too? Obviously a list with only one element is ordered, yet you have no provision for expressing that: it fits neither your base case nor your recursive case.
The single-element list is another case hiding here that you haven't addressed yet. Since this is independent of the two rules you've already defined, you might want to consider a way to address this special case separately.
Well that, in the end, was rediculously easy to fix.
Here is the correct code.
ordered([]).
ordered([N, M|Ns]):-
append([M], Ns, Tail),
ordered(Tail),
N =< M.
ordered([M]).
ordered([M]). deals with the single-element list as described above.
The real root of my problem was not including [] around the M in the append function.
Whats the ettiquette regarding awarding the correct answer? You've both helped muchly.
Jon
Don't use append/3.
edit1 to satisfy #false. In order to make it tail recursive friendly it has to eliminate backtracking. This is tail-recursive and only slight variation on #Xonix:
ordered([X|[]]):-!.
ordered([X,Y|Ys]) :-
X =< Y,
!,
ordered([Y|Ys]).
edit2 Take it a step further to eliminate lists that have less than two elements
ordered([X,Y|[]]):- X =< Y,!.
ordered([X,Y|Ys]) :-
X =< Y,
!,
ordered([Y|Ys]).