Related
I am trying to write a predicate that will be true if X is a sublist of Y, without taking into account the first term and the last term of Y. For example, query listWithinList([b,c,d],[a,b,c,d,e]) would return True, but query listWithinList([b,c,d,e],[a,b,c,d,e]) would yield False because e, the last element of Y, should not be part of X.
Currently I have
listWithinList(X,Y):-append(_,Y2,Y), append(X,_,Y2).
but I am not sure how to change the code so that it does the same trick but without taking into account the first and last term of Y.
When you write _ in an argument to append, it refers to an arbitrary list. So arbitrary that its length is arbitrary too.
For example:
?- append(_, Suffix, [a, b, c]).
Suffix = [a, b, c] ;
Suffix = [b, c] ;
Suffix = [c] ;
Suffix = [] ;
false.
Here _ can stand for any of the lists [], [a], [a, b], [a, b, c]. But I don't need to tell you this. Prolog can tell you this if you give the anonymous variable _ a proper name instead:
?- append(Prefix, Suffix, [a, b, c]).
Prefix = [],
Suffix = [a, b, c] ;
Prefix = [a],
Suffix = [b, c] ;
Prefix = [a, b],
Suffix = [c] ;
Prefix = [a, b, c],
Suffix = [] ;
false.
In contrast, the term [_] stands not for an abitrary list. It stands for a list that definitely has exactly one element. That element (denoted _) is arbitrary.
For example:
?- append([_], Suffix, [a, b, c]).
Suffix = [b, c].
Or, again, with a proper variable name so we can see the binding:
?- append([X], Suffix, [a, b, c]).
X = a,
Suffix = [b, c].
All this is to say that the definition from the question:
listWithinList(X,Y):-append(_,Y2,Y), append(X,_,Y2).
Is close to being correct. But the two uses of _ don't "remove" one element each. They "remove" an arbitrary number of elements each. So you don't just get the middle of the list:
?- listWithinList(Middle, [a, b, c, d, e]).
Middle = [] ;
Middle = [a] ;
Middle = [a, b] ;
Middle = [a, b, c] ;
Middle = [a, b, c, d] ;
Middle = [a, b, c, d, e] ;
Middle = [] ;
Middle = [b] ;
Middle = [b, c] ;
Middle = [b, c, d] ;
Middle = [b, c, d, e] ;
Middle = [] ;
Middle = [c] ;
Middle = [c, d] ;
Middle = [c, d, e] ;
Middle = [] ;
Middle = [d] ;
Middle = [d, e] ;
Middle = [] ;
Middle = [e] ;
Middle = [] ;
false.
If we want to "remove" lists of exactly one element from the front and the back, we must write [_]:
listWithinList(X, Y) :-
append([_], Y2, Y),
append(X, [_], Y2).
This now behaves like this:
?- listWithinList(Middle, [a, b, c, d, e]).
Middle = [b, c, d] ;
false.
Additionally, note the difference between [_] and [_|_]. The former stands for a list of exactly one element. The latter stands for a list of one or more elements. In this case you don't want to "remove" more than one element, so using [_|_], like one of the other answers suggests, is absolute nonsense.
Finally, Prolog can suggest a further simplification to us:
?- append([X], Xs, Ys).
Ys = [X|Xs].
Appending a one-element list [X] and an arbitrary list Xs gives a list that we can also write as [X | Xs] without using append. So one of the append calls is not needed. I might write this predicate like this:
list_middle(List, Middle) :-
append([_First | Middle], [_Last], List).
And use it like this:
?- list_middle([a, b, c, d, e], Middle).
Middle = [b, c, d] ;
false.
Or like this:
?- list_middle(List, [1, 2, 3]).
List = [_2658, 1, 2, 3, _2664].
Grammars are very intuitive for such tasks. Just describe what we have:
list_within(Xs, Ys) :-
phrase(( [_First], seq(Ys), [_Last] ), Xs).
seq([]) --> [].
seq([E|Es]) --> [E], seq(Es).
That is, first the element _First, then the sequence Ys, and finally the element _Last.
Due to how lists are represented in Prolog, you can easily remove the first element by destructuring it as its head and tail, and unifying the result with tail, as follows:
tail([_|L], L).
On success, the predicates unifies the second parameter with the tail of the first.
To remove the last element, you can say that your input list is the result of appending a prefix to a list of one element (whose value is not important):
butlast(List, Prefix) :-
append(Prefix, [_LastValue], List).
You can combine them both to remove both extremities:
chop(List, Middle):
tail(List, Tail),
butlast(Tail, Middle).
Here is my approach:
First: Create all combinations of the List that are acceptable when the first letter is removed and last letter is removed.
listWithinList(M,L):-
append([_|_],L2,L),
append(S,[_|_],L2),
The first append removes the first element from the list, and the second append removes the last element from the list. The combinations of List are stored in S.
Second: We use the same predicate to check if M is same as any of the combinations in S.
same(L1,L2):-
L1==L2.
Putting the code together:
listWithinList(M,L):-
append([_|_],L2,L),
append(S,[_|_],L2),
( same(M,S)->write(S),
write('This combination is correct.') ).
same(L1,L2):-
L1==L2.
Examples:
?-listWithinList([b,c,d],[a,b,c,d,e]).
[b, c, d]This combination is correct.
1true
false
?-listWithinList([b,c,d,e],[a,b,c,d,e]).
false
?-listWithinList([a,b,c,d,e],[a,b,c,d,e]).
false
I am trying to implement a partition predicate in Prolog that splits a list into its two halves, a Prefix and a Suffix, of approximately same lengths.
partition(L,P,S)
Where prefixes and suffixes are defined as such:
prefix(P,L) :- append(P,_,L).
suffix(S,L) :- append(_,S,L).
If L is [], then Prefix and S are [].
If L is [H], then P is [H] and S is [].
If L has two or more elements, this is how the list is partitioned into its prefix and suffix:
Length of L is N and the length of P is div(N,2). The length of S is N - div(N,2).
So for instance:
?- partition([a,b,c,d],X,Y).
X = [a,b]
Y = [c,d]
?- partition([a],X,Y).
X = [a]
Y = [ ]
Here is my code and the error I get:
partition([],[],[]).
partition([H],[H],[]).
partition(L, P, S) :-
length(L, N),
Plen is div(N,2),
Slen is N - div(N,2),
length(Pre, Plen),
length(Suff, Slen),
prefix(Pre, L),
suffix(Suff, L),
P is Pre,
S is Suff.
partition([a,b,c,d],X,Y).
>>> Type error: `[]' expected, found `[a,b]' (a list)
("x" must hold one character)
I don't understand this error message but this is wrong:
P is Pre,
S is Suff.
This is for arithmetic evaluation whereby the Right-Hand-Side is evaluated as an arithmetic expression and unified with the Left-Hand-Side.
You just want to unify the variables:
P = Pre,
S = Suff.
Alternatively, you can use the same same for P and Pre / S and Suff throughout.
If you change is to to = as suggested by David Tonhofer's answer, the whole thing works.
But I would like to add that you are complicating things a bit. You have identified correctly that append/3 can be used to compute list prefixes and suffixes. But for any list to be partitioned and any prefix, the suffix is unique, and is already computed by append/3! And the other way round: If you ask it to compute a suffix, it will also compute the prefix you seek. But then you throw these answers away and try to recompute a matching prefix or suffix. There is no need to do that.
If we make your prefix and suffix predicates a bit more explicit:
list_prefix_theonlypossiblematchingsuffix(List, Prefix, TheOnlyPossibleMatchingSuffix) :-
append(Prefix, TheOnlyPossibleMatchingSuffix, List).
list_suffix_theonlypossiblematchingprefix(List, Suffix, TheOnlyPossibleMatchingPrefix) :-
append(TheOnlyPossibleMatchingPrefix, Suffix, List).
We can see that once we have a given prefix for a list, there really is no more choice for the suffix (and vice versa):
?- list_prefix_theonlypossiblematchingsuffix([a, b, c, d], Prefix, MatchingSuffix).
Prefix = [],
MatchingSuffix = [a, b, c, d] ;
Prefix = [a],
MatchingSuffix = [b, c, d] ;
Prefix = [a, b],
MatchingSuffix = [c, d] ;
Prefix = [a, b, c],
MatchingSuffix = [d] ;
Prefix = [a, b, c, d],
MatchingSuffix = [] ;
false.
So there is no need to try to compute the prefix and suffix separately and to match up their lengths. It's enough to restrict the prefix, as the suffix will follow:
partition(List, Prefix, TheOnlyPossibleMatchingSuffix) :-
length(List, N),
PrefixLength is N div 2,
length(Prefix, PrefixLength),
list_prefix_theonlypossiblematchingsuffix(List, Prefix, TheOnlyPossibleMatchingSuffix).
This works as you want:
?- partition([a, b, c, d], Prefix, Suffix).
Prefix = [a, b],
Suffix = [c, d].
?- partition([a, b, c, d, e], Prefix, Suffix).
Prefix = [a, b],
Suffix = [c, d, e].
Once you have this, it's much clearer to replace the goal involving list_prefix_verylongpredicatename with what is really meant:
partition(List, Prefix, Suffix) :-
length(List, N),
PrefixLength is N div 2,
length(Prefix, PrefixLength),
append(Prefix, Suffix, List).
Coming from other programming languages it may be a bit unusual that a predicate like append/3 computes several things at once that have a deep relationship with each other, i.e., a prefix and the unique matching suffix. But this is one of the things that makes Prolog so expressive and powerful. Get used to it and profit from it!
It seems to me that you're doing a lot of unnecessary work here.
This is all I think you need:
partition(L,P,S) :-
partition(L,L,P,S).
partition(L,[],[],L).
partition(([H|L],[_],[H],L).
partition([H|L],[_,_|L2],[H|P],S) :-
partition(L,L2,P,S).
If I query ?- partition([a],X,Y), write([X,Y]). then I get:
[[a], []]
true.
If I query ?- partition([a,b,c,d,e],X,Y), write([X,Y]). then I get:
[[a, b, c], [d, e]]
true.
Since you've already defined your prefixes and suffixes as
prefix(P,L) :- append(P, _, L). % prefix
suffix(S,L) :- append(_, S, L). % suffix
just smash the two together into one call,
partition(L,P,S) :-
append(P, S, L),
and this would be it, except you have additional conditions about the comparative lengths of the two near-halves, so just add them into the mix:
length( P, N), length( A, N), % same length, fresh list A
(A = [_|S] ; A = S). % S one shorter than P, or same length
And that's that. Testing:
2 ?- partition( [1,2,3], A, B ).
A = [1, 2],
B = [3].
3 ?- partition( L, [1,2], [3] ).
L = [1, 2, 3].
15 ?- partition( L, A, B ).
L = A, A = B, B = [] ;
L = A, A = [_G2477],
B = [] ;
L = [_G2477, _G2483],
A = [_G2477],
B = [_G2483] ;
L = [_G2477, _G2483, _G2492],
A = [_G2477, _G2483],
B = [_G2492] ;
L = [_G2477, _G2483, _G2489, _G2492],
A = [_G2477, _G2483],
B = [_G2489, _G2492]
....
I have the following problem.
I'm given a listOfLists, a value (row,col) and I need to get the list inside a list that contains that certain value, up to my value's index inside that list.
For example
?- find_list([[(1,2),(1,3),(1,4)], [(2,2),(2,3),(2,4)]], (1,3), List2).
List2 = [(1,2),(1,3)].
My problem is that if I use member/2 I will only get true or false for if my value is inside listOfList or not, and not the list that I will need to be working with.
How can I get that list that has my value inside it?
Does it matter that the values are two-dimensional coordinates? Is there an ordering on them that you must respect, or is it simply the ordering of the elements in the list? I will assume the latter.
If you want to split a list at some point, the standard append/3 predicate is usually the way to go. For example, assume we want to cut the list [a, b, c, d, e] into a prefix containing the elements before c and a suffix containing the elements after c. Here is how that is done:
?- append(Prefix, [c | Suffix], [a, b, c, d, e]).
Prefix = [a, b],
Suffix = [d, e] ;
false.
Here c is excluded from the prefix, but that's easy to fix:
?- append(Prefix, [c | Suffix], [a, b, c, d, e]), append(Prefix, [c], UpToAndIncludingC).
Prefix = [a, b],
Suffix = [d, e],
UpToAndIncludingC = [a, b, c] ;
false.
We can give this predicate a nice name:
list_pivot_prefix(List, Pivot, Prefix) :-
append(Prefix0, [Pivot | _Suffix], List),
append(Prefix0, [Pivot], Prefix).
And your find_list/3 predicate then simply finds all the lists in the given list of lists for which this relation holds:
find_list(Lists, Element, Prefix) :-
member(List, Lists),
list_pivot_prefix(List, Element, Prefix).
Here is your test case:
?- find_list([[(1,2),(1,3),(1,4)],[(2,2),(2,3),(2,4)]],(1,3),List2).
List2 = [ (1, 2), (1, 3)] ;
false.
So i have this code which copies everything from a list to another one.
How should I modify it in order to copy, lets say the first two character.
$copy(L,R) :-
copy2(L,R).
copy2([X],[X]).
copy2([H|T1],[H|T2]) :-
copy2(T1,T2).
example of what i want it to be: ?- copy([a,b,c,d,e,f],X,2). --> X = [a,b]
You can copy lists just with unification:
?- [a,b,c,d,e] = List.
List = [a, b, c, d, e].
?- [a,b,c,d,e] = [V,W,X,Y,Z].
V = a,
W = b,
X = c,
Y = d,
Z = e.
?- [a,b,c,d,e] = [V,W|Rest].
V = a,
W = b,
Rest = [c, d, e].
A predicate like the one you describe, copying the first N elements of a list, can be defined thus:
first_n(List, N, Xs) :-
length(Xs, N),
append(Xs _, List).
Which works like so:
?- first_n([a,b,c,d,e], 2, X).
X = [a, b].
There are a bunch of different ways to write a similar predicate. The way I have defined first_n/3, it will fail if N is larger than the length of List (this was pointed to out by #false in the comments). One could instead write an analog of the common function take, which will return List in its entirety in the event that N is greater than List's length:
take_n(N, List, Taken) :-
( length(List, M),
N > M
->
Taken = List
;
length(Taken, N),
append(Taken, _, List)
).
This answer was corrected (several times) under the guidance of #false's helpful criticism.
I can add a single object to a list with this code and query:
makelist(A, B, C, X) :- append([1, 2, 3],A, X).
?- makelist(a, b, c, X).
X = [1, 2, 3|a].
However rather than the usual separator comma (,) there's a vertical line separator (|) and I cannot add another object to the same list:
makelist(A, B, C, X) :- append([1, 2, 3],A, X), append(X,B, X).
?- makelist(a, b, c, X).
false.
There are several misunderstandings. First, lists and their elements are confused which leads to the "dotted pair" that is |a]. Then, it seems that the role of variables is not clear to you.
In the goal append([1,2,3],A,X) both A and X are supposed to be lists. However, you set A to a which is not a list. The problem behind is that append/3 accepts any term for the second argument. To see this, just look at its answers:
?- append([1,2,3],A,X).
X = [1,2,3|A].
So the A can be anything, but it should be rather only a list.
?- A = a, append([1,2,3],A,X).
A = a, X = [1,2,3|a].
Note that append/3 insists that the first argument is a list (or a partial list). Then once you have a bad list, you can no longer append it further. That is:
?- A = a, append([1,2,3],A,X), append(X, _, _).
false.
Note that I did not use your definition literally. Instead, I replaced certain arguments by _ since they cannot help.
The second problem stems from the goal append(X, B, X). This goal, can only be true if B = []. Let's try this out:
?- append(X, B, X).
X = [], B = []
; X = [_A], B = []
; X = [_A,_B], B = []
; X = [_A,_B,_C], B = []
; ... .
And:
?- B = [_|_], append(X, B, X).
loops.
While there are many answers for X, B is always [].
append appends lists. So you want to make a list with a single element to append it to another list:
makelist(A, B, C, X) :- append([1, 2, 3], [A], X). % What's the purpose of B and C, btw?
Also you can add items to the beginning of a list more effectively:
makelist(A, B, C, [A | [1, 2, 3]]).