Accessing elements inside parenthesis in Prolog - list

So i have this predicate letras_comuns(Lst_Pals, Letras_comuns) in which Lst_Pals is a list of like [[a,t,o],[a,c,o],[a,n,o]] and Letras_comuns is the a list with all the elements common in every word at a given index, e.g. [(1,a), (3,o)].
Example:
?- Lst_Pals = [[a,t,o], [a,c,o], [a,n,o], [a,l,o]],
letras_comuns(Lst_Pals, Letras_comuns).
Lst_Pals = [[a, t, o], [a, c, o], [a, n, o], [a, l, o]],
Letras_comuns = [(a, 1), (o, 3)].
So basically what this means is that all the words in Lst_pals have an a in the 1st index and an o in the 3rd/last index.
The problem is that i want to access to the elements inside the parenthesis and i know if put (X,Y) = (a,1) i can access its elements, the thing is that this only works for 1 and i want to access to all of them, so anyone can tell me how because i'm clueless on how to do this.

You can define
p( (X,Y), X, Y ).
then use it:
?- p( (a,1), A, I ).
A = a,
I = 1.
or
?- maplist( p, [(a, 1), (o, 3)], AS, IS).
AS = [a, o],
IS = [1, 3].

Related

checking common letters in a certain index in a list of lists

So i have this predicate letras_comuns(Lst,Common_ltrs) in which Lst is a list of words like [[a,n,o],[a,c,o],[a,t,o]] and Commons_ltrs is the result of the common letters in all of those words at a certain index.
Example:
Lst_Pals = [[a,t,o], [a, c, o], [a,n,o], [a,l,o]], letras_comuns(Lst_Pals, Letras_comuns).
Lst_Pals = [[a,t,o], [a, c, o], [a,n,o], [a,l,o]],
Letras_comuns = [(1, a),(3, o)].
So what this [(1, a), (3, o)]. means is that all of the words have an a at the first index and that all of the words have an o at the 3rd index
Well to this i did this auxiliar predicate letras_comuns_aux(Lst,Letra_comum,Index). in which Lst is the same as before, Letra_comum is the common letter in all of the words at a given index, like [(1, a)] and index the specific index.
Example:
?- letras_comuns_aux([[a,t,o], [a, c, o], [a,n,o], [a,l,o]],Letra_comum,1).
Letra_comum = [(1, a)].
?- letras_comuns_aux([[a,t,o], [a, c, o], [a,n,o], [a,l,o]],Letra_comum,3).
Letra_comum = [(3, o)].
So basically this is giving the result i want at given index and this predicate is working fine, having said this what i tried to do is to do this verification for all indexes in Lst.
The problem is that for some reason this is giving an infinite cicle and i dont understand why.
Program:
letras_comuns_aux([],AC,_,_,AC) :- !.
letras_comuns_aux([P|R],Letra_comum,Index,El,_) :-
nth1(Index,P,Ind_P),
Ind_P == El,!,
NAC = [(Index,El)],
letras_comuns_aux(R,Letra_comum,Index,El,NAC).
letras_comuns_aux(_,Letra_comum,Index,El,_) :-
NAC = [],!,
letras_comuns_aux([],Letra_comum,Index,El,NAC).
letras_comuns(Lst_Pals, Letras_comuns) :-
length(Lst_Pals,C),
NC is C + 1,
letras_comuns(Lst_Pals,Letras_comuns,[],NC,1).
letras_comuns(_, AC,AC,Comp,Comp).
letras_comuns(Lst_Pals, Letras_comuns,AC,Comp,Cont) :-
letras_comuns_aux(Lst_Pals,Letra_comum,Cont),
append(AC,Letra_comum,NAC),
NCont is Cont +1,
letras_comuns(Lst_Pals, Letras_comuns,NAC,Comp,NCont).
This is clearly an endless loop:
letras_comuns_aux(_,Letra_comum,Index,El,_) :-
NAC = [],!,
letras_comuns_aux([],Letra_comum,Index,El,NAC).
At every call, NAC is a fresh variable, that thereof will obviously will bind the empty list, and the recursive call then will receive such empty list as last parameter. What's the purpose of it ?
Now forgive my lazyness, but to understand your program is clearly more work than suggest a simpler idiomatic way:
letras_comuns(Lst_Pals, Letras_comuns) :-
findall((L,I), foreach(member(X,Lst_Pals),nth1(I,X,L)), Letras_comuns).
This gives
?- Lst_Pals = [[a,t,o], [a, c, o], [a,n,o], [a,l,o]],
| letras_comuns(Lst_Pals, Letras_comuns).
Lst_Pals = [[a, t, o], [a, c, o], [a, n, o], [a, l, o]],
Letras_comuns = [(a, 1), (o, 3)].
and is made possible by foreach/2, that keeps variables bindings among successive calls of Generator.

Trying to Implement a Split Predicate in Prolog

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]
....

Add non repeating elements to List in Prolog

I have a List and I am trying to add to it elements from another list that are not already present in the first List.
So if I had 2 Lists :
[a, b, 3, c]
[2, a, b, 4]
The output would be:
[a, b, 3, c, 2, 4]
I am able to get it in reversed order but not in the correct one, here is what I am trying to do:
add_to_list(L, [], L).
add_to_list(List, [H|T], [H|Res]) :-
\+ member(H, List),
add_to_list(List, T, Res).
add_to_list(List, [H|T], Res):-
add_to_list(List, T, Res).
And when I do the method with the 2 Lists mentioned above the output I get is:
[2, 4, a, b, 3, c]
I am aware that my ending clause is adding the L to the end of the result I get, which is why the order is a mess but how can I do it the correct way?
Well the problem here is that you should first move to the end of the first list before concatenating data.
We can still use the code you have written, but alter it slightly like:
atl(_, [], []).
atl(List, [H|T], R) :-
( member(H, List)
-> R = Res
; R = [H|Res]
),
atl(List, T, Res).
We here basically made three changes: (a) we renamed addToList/3 to atl/3; we changed L to [] in the first line; and (c) we used an if-then-else to prevent that the third clause gets triggered even if H is not a member of List (this was a semantical error in your code).
Now we will obtain for the given input as output:
?- atl([a, b, 3, c] , [2, a, b, 4], R).
R = [2, 4] ;
false.
So now we can write an addToList/3 in terms of atl/3: we first generate the list of items to append, and next we use append/3 to append these at the end of the list:
addToList(A, B, L) :-
atl(A, B, R),
append(A, R, L).

minimum in list of lists in prolog

hello i have a list like this:
[[3,[a,b,c,d]],[2,[a,b,d]],[5,[d,e,f]]]
list of lists...
i want to find the minimum number on inner list
in this case i want to return D=2 and L=[a,b,d]
i tried this code:
minway([[N|L]],N,L).
minway([[M|L1]|L2],D,_):- M<D, minway(L2,M,L1).
minway([[M|_]|L2],D,L):- M>=D, minway(L2,D,L).
but i got error:
</2: Arguments are not sufficiently instantiated
Exception: (8) minway([[3,[a,b,c,d]],[2,[a,b,d]],[5,[d,e,f]]], _G7777, _G7778) ?
creep
for this run sentence:
minway([[3,[a,b,c,d]],[2,[a,b,d]],[5,[d,e,f]]],D,L).
the result need to be:
D=2.
L=[a,b,d].
where my problem?
and how to fix it?
tnx a lot
First, switch to a better data representation: Instead of [Key,Value], use Key-Value!
Then, define minway_/3 based on
iwhen/2,
ground/1,
keysort/2, and
member/2, like so:
minway_(Lss, N, Ls) :-
iwhen(ground(Lss), (keysort(Lss,Ess), Ess = [N-_|_], member(N-Ls, Ess))).
Sample query using SICStus Prolog 4.5.0:
| ?- minway_([3-[a,b,c,d],2-[a,b,d],5-[d,e,f],2-[x,t,y]], N, Ls).
N = 2, Ls = [a,b,d] ? ;
N = 2, Ls = [x,t,y] ? ;
no
There are a couple of fundamental issues.
One is in your problem lies in your representation of a list. Your predicates seem to assume that, for example, [3, [a,b,c]] is represented as [3 | [a,b,c]] but it is not. The list [3 | [a,b,c]] is the list with 3 as the head, and [a,b,c] as the rest of the list or the tail. In other words, [3 | [a,b,c]] is [3, a, b, c].
And, so, your base case would be:
minway([[N,L]], N, L).
The second issue is in your other predicate clauses. There's no starting point for D. In other words, it's never given a value to start with, so you get an instantiation error. You cannot compare N > D if one of the variables doesn't have a value.
When doing a minimum or maximum from scratch, a common approach is to start by assuming the first element is the candidate result, and then replace it if you find a better one on each step of the recursion. It also means you need to carry with you the last candidate at each recursive call, so that adds extra arguments:
minway([[N,L]|T], D, R) :-
minway(T, N, L, D, R).
minway([], D, R, D, R). % At the end, so D, R is the answer
minway([[N,L]|T], Dm, Rm, D, R) :-
( N < Dm
-> minway(T, N, L, D, R) % N, L are new candidates if N < Dm
; minway(T, N, Dm, Rm, D, R) % Dm, Rm are still best candidate
).
In Prolog, you can simplify this a little since Prolog has a more general term comparison operator, #<, #>, etc, which is smart about comparing more complex terms. For example, [2, [d,e,f]] #< [3, [a,b,c]] is true since 2 < 3 is true. We can then write:
minway([H|T], D, R) :-
minway(T, H, D, R).
minway([], [D, R], D, R).
minway([H|T], M, D, R) :-
( H #< M
-> minway(T, H, D, R)
; minway(T, M, D, R)
).
You can do this by using the minimum predicate. Findall can be very helpful.
min([X],X).
min([H|T],Min):-
min(T,TMin),
H>TMin,
Min is TMin.
min([H|T],Min):-
min(T,TMin),
H=<TMin,
Min is H.
minway(List,D,L):-
findall(Value,member([Value,_],List),VList),
min(VList,Min),
D=Min,
findall(EList,member([Min,EList],List),L).
?-minway([[3,[a,b,c,d]],[2,[a,b,d]],[5,[d,e,f]]],D,L).
D = 2,
L = [[a, b, d]]
Try library(aggregate):
?- aggregate_all(min(X,Y),
member([X,Y], [[3,[a,b,c,d]],
[2,[a,b,d]],
[5,[d,e,f]]]),
min(D,L)).
D = 2,
L = [a, b, d].
See also here:
Aggregation operators on backtrackable predicates
https://www.swi-prolog.org/pldoc/man?section=aggregate

Prefix in Prolog

I'm new in Prolog.
I have a problem about predicate prefix but a little bit different.
I want to get a prefix of a list but until an element
The list can have repeat elements.
An example:
prefix(Element, List, Prefix)
prefix(c, [a,b,c,d,e,f], [a, b])
The element is not included.
What I have so far is this
prefix(X, [X|T], []).
prefix(X, [Y|T], [Y|Z]):-
prefix(X, T, Z).
But it does not work.
L = [a,b,c] ? prefix(b, L, Prefix).
no
?-
Thanks
With dif/2 you can explicitly state that for any member X preceding Element, X \== Element:
prefix(Element, [Element|_], []).
prefix(Element, [Head|List], [Head|Prefix]) :-
dif(Element, Head),
prefix(Element, List, Prefix).
or equally, because I wanted to use append/3 in the first iteration of my answer:
prefix(Element, List, Prefix) :-
append(Prefix, [Element|_Suffix], List),
maplist(dif(Element), Prefix).
For the suffix it is basically the same:
suffix(Element, List, Suffix) :-
append(_Prefix, [Element|Suffix], List),
maplist(dif(Element), Suffix).
If you don't want to use maplist(dif(Element), List):
all_dif(_, []).
all_dif(X, [H|T]) :- dif(X, H), all_dif(X, T).
Here is a solution using Definite Clause Grammars dcg and the non-terminal all_seq//2:
prefix(X, Xs, Ys) :-
phrase( ( all_seq(dif(X), Ys), [X], ... ), Xs).
... --> [] | [_], ... .
So the grammar (within phrase/2) reads:
There is
1. an initial sequence Ys with all elements different to X, followed by 2. X, followed by 3. anything.
There is still a downside, which is often the case when using DCGs: The implementation is not as determinate as it could be and thus leaves superfluous choicepoints around.
prefix(X,[X|T],[]).
prefix(X,[Y|T],Z) :- prefix(X,T,M) , Z = [Y|M].
output:
?- L = [a,b,c,d,e,f] , prefix(d,L,G). L = [a, b, c, d, e, f], G = [a,
b, c] .
?- L = [a,b,c,d,e,f] , prefix(e,L,G). L = [a, b, c, d, e, f], G = [a,
b, c, d] .
EDIT #1
the original code is working , use (,) instead of (?) as following.
prefix(X,[X|T],[]).
prefix(X,[Y|T],[Y|Z]) :- prefix(X,T,Z).
output:
?- prefix(d , [a,b,c,d,e] , G). G = [a, b, c]
?- L = [a,b,c] , prefix(b, L, Prefix).
L = [a, b, c],
Prefix = [a] .
EDIT #2
as user false mentioned in comment, I can confirm that you are right, but in my solution, I assume that the list contains unique elements:
prefix(d,[d,d],[d]) succeeds - it should fail ,