I'm doing an exercise in Prolog using SWI-Prolog, to take a nested list and convert it into a list of elements and then make the sum of the elements, I made two separate predicates which make me both functionalities:
my_flatten(X,[X])->Transform a list, possibly holding lists as elements into a 'flat' list by replacing each list with its elements (recursively).
my_flatten(X,[X]) :- \+ is_list(X).
my_flatten([],[]).
my_flatten([X|Xs],Zs) :-
my_flatten(X,Y), my_flatten(Xs,Ys), append(Y,Ys,Zs).
addList-> Adds all the elements of a list and returns their sum
addList([],0).
addList([X|Xs],N):-
addList(Xs,N0),N is X+N0.
The problem itself is that I'm new programming in Prolog and I don't know how join both predicates in the same predicate, so that the list returned by my_flattern be used by the predicate addList. Maybe it's a bit foolish question, but I've been stuck on it for days. I need some help to clarify this question for other problems
To construct a new predicate which does both, simply call both my_flatten and addList, with a shared variable:
addListFlattened(L, Sum) :-
my_flatten(L, L2),
addList(L2, Sum).
addListFlattened is a new predicate (you can change the name), which reuses addList.
Related
intersection([],L1,L2,L3).
intersection([H|T],L2,L3,[H|L4]):-member(H,L2),intersection(T,L3,L3,L4).
member(H,[H|T]).
member(X,[H|T]):-member(X,T).
This code makes the third list from the first and second list.
last([U],U).
last([_|L3],U) :- last(L3,U).
This piece of code looks for the last item in the list.
My problem is that I can’t figure out how to make these two pieces of code fit into one. That is, the program should find duplicate elements in the first and second list and display them in the third, and from the third list, display the last element multiplied by 3.
The main problem is intersection/4. I assume you wanted to write a deterministic predicate intersection/3 the first two arguments of which are fully instantiated at call time and the last argument of which is an output argument. By deterministic, I mean that intersection/3 should succeed exactly once without leftover choice points. The SWI-Prolog documentation contains a useful overview of determinism and mode declarations (although it does not enforce them).
It is useful to begin by writing a declarative specification of the predicate following the inductive definition of lists:
The intersection of [] and Ys is [].
The intersection of [A|Xs] and Ys is A prepended to the intersection of Xs and Ys if A is a member of Ys.
The intersection of [A|Xs] and Ys is the intersection of Xs and Ys if A is not a member of Ys.
The simplest translation of this specification into standard Prolog is:
intersection([],_,[]).
intersection([A|Xs],Ys,[A|Zs]) :-
member(A,Ys),
intersection(Xs,Ys,Zs).
intersection([A|Xs],Ys,Zs) :-
\+ member(A,Ys),
intersection(Xs,Zs).
If the first call to member/2 succeeds the second should fail. In order to avoid backtracking, unifying the current goal with the head of the second clause, and performing a redundant call to member/2, we place a cut after the occurrence of member/2 in the second clause.
intersection([],_,[]).
intersection([A|Xs],Ys,[A|Zs]) :-
member(A,Ys),
!,
intersection(Xs,Ys,Zs).
intersection([_|Xs],Ys,Zs) :-
intersection(Xs,Ys).
If the current goal unifies with the head of the first clause, it will not unify with the heads of later clauses. In order to prevent spurious backtracking, we place a cut in the (empty) body of the first clause. Whether this cut is necessary depends on your choice of Prolog implementation.
intersection([],_,[]) :-
!.
intersection([A|Xs],Ys,[A|Zs]) :-
member(A,Ys),
!,
intersection(Xs,Ys,Zs).
intersection([_|Xs],Ys,Zs) :-
intersection(Xs,Ys).
We are only interested in checking membership in the second list. Thus, we can replace the occurrence of member/2 with the semideterministic predicate memberchk/2. Here, semideterministic means that memberchk/2 succeeds or fails exactly once without leftover choice points.
intersection([],_,[]).
!.
intersection([A|Xs],Ys,[A|Zs]) :-
memberchk(A,Ys),
!,
intersection(Xs,Ys,Zs).
intersection([_|Xs],Ys,Zs) :-
intersection(Xs,Ys).
This implementation of intersection/3 is nearly identical to the implementation found in the SWI-Prolog library lists.pl. You can combine this predicate with an implementation of last/2 in order to complete your program. For example:
last_duplicate_tripled(Xs,Ys,N) :-
intersection(Xs,Ys,Zs),
last(Zs,M),
N is M * 3.
From here, I recommend doing the following:
Implement intersection/3 using metalogical predicates like findall/3.
Read #false's answer to this question.
Read #repeat's answer to this question.
They are doing something much more interesting and sophisticated than I attempted in this answer.
Lets say I have a list of lists like this in prolog [[1,2],[3,4,2],[5,6,1]].
I need to be able to get every lists of unitary lists that I can get out of that general list. That means that in the first list a 1 or a 2 can be there. On the second list a 3, 4, or 2 can be there, etc. But each number can only be repeated once in the final list of unitary lists.
What I mean is:
We find the first list with more than one element and choose one random
[[1],[3,4,2],[5,6]] we propagate the change and remove the 1 from the last list since we can't pick it there now. That I know how to do.
Now we go and choose the second list because it is not unitary and choose for example the first item [[1], [3], [5,6]].
And we do that until we get a list of unitary lists [[1], [3], [5]].
But there are other options like if we had chosen the 2 on the first list [[2], [3,4], [5,6,1]] -> [[2], [3], [5]].
etc, etc. How can I in Prolog try every option until I find one that respects my goal?
What I have right now is this (the predicate is_solution checks if the input satisfies my goal):
solve(List, Solution) :-
is_solution(List),
Solution = List.
solve(List, Solution) :-
does_something_here
Which I don't know what to do. I have the idea that I need to do some sort of DFS (I guess?) to transverse for every option of choices until I find one that fits but I've still not fully grasped the Prolog way of thinking. Can anyone help with this problem?
EDIT: To get a list of lists of unitary lists (triple nested like this [[[1,2], [3,4]], [[6,7], [3,4]]]) I built this which seems to work now since I fixed it
list_relation(List1, List2) :-
maplist(sublist_relation, List1, List2).
sublist_relation(SubList1, SubList2) :-
maplist(element_relation, SubList1, SubList2).
element_relation(Element1, Element2) :-
member(X, Element1),
length(Element2, 1),
member(X, Element2).
You don't have much to go on, so I'll provide some hints.
First of all, this is a common pattern in Prolog where you want to describe a relation between two lists with a one-to-one relationship between the corresponding elements. Such a pattern might look something like this:
list_relation([], []). % The empty list is related to the empty list
list_relation([H1|T1], [H2|T2]) :-
% Code here that describes the relation between H1 and H2
list_relation(T1, T2). % Recursively check the relation on the tails
This is so common, in fact, there's a maplist predicate that can handle the mapping for you:
list_relation(List1, List2) :-
maplist(element_relation, List1, List2).
element_relation(Element1, Element2) :-
% Code here that describes the relation between Element1 and Element2
In your specific case, your elements are lists and you want to pick out elements. The "relation" between an element in the first list and a corresponding element of the second list can be described using the member/2 predicate. member(X, List) succeeds with X being an element of list List.
I leave you with those clues.
As an addendum, your updated question overuses maplist and has an overly complicated way of expressing a list of one element. Your attempt does a sublist relation, which I did not say was necessary, nor is it.
So if you follow what I wrote above, your element_relation would be expressed as:
element_relation(List, [E]) :-
member(E, List).
It's as simple as that. So the complete solution looks like:
list_relation(List1, List2) :-
maplist(element_relation, List1, List2).
element_relation(List, [E]) :-
member(E, List).
Note that List in the element_list corresponds to an element in your first list. That element is, itself, a list. The second argument to element_list gives the single-element list of the element chosen from List. This choice is made with member(E, List).
Finally, please use sensible names for your predicates. I chose generic names to explain the principle. list_relation and element_relation are very general and do not describe your particular problem. You should name appropriately.
Suppose I have a list of lists
L= [[1,2,3], [3,2,1],[2,1,2],[3,1,2], [1,2,2]].
as you can see, [1,2,3],[3,2,1] and [3,1,2] are permutations of each other.
[2,1,2] and [1,2,2] are also permutations of each other.
My goal is to remove all permutations of elements in the list.
the result list should be:
L'=[[1,2,3],[2,1,2]].
My idea so far is use member(X,L) to locate an element in the list, then use permutation(X,Xperm) to get a permutation of X, then check if Xperm
is in L , and if so ,delete it.
However the result turns out not to be what I wanted.
Could anyone help me?
One way to eliminate the duplicates is to use the standard recursive process for removing duplicates, but rather than checking equality directly through unification, change the code to try unifying sorted lists.
/* This is the regular duplicate elimination
that sorts the head element before checking for duplicates
*/
remove_dups([],[]).
remove_dups([H|T], TT) :- msort(H,SH), contains_dup(SH,T), remove_dups(T, TT).
remove_dups([H|T], [H|TT]) :- msort(H,SH), \+ contains_dup(SH,T), remove_dups(T, TT).
/* This duplicate checker routine sorts the lists before trying to unify them */
contains_dup(_, []) :- fail.
contains_dup(SH, [H|_]) :- msort(H, SH).
contains_dup(SH, [_|T]) :- contains_dup(SH, T).
The code uses SWI's msort/2 predicate.
Here is a demo on ideone.
Last time I did anything with Prolog was over 20 years ago, so I don't remember anything Prolog specific.
However, if I were to do this in any functional-friendly language, I would sort all the sublists in the big list, and then remove all the duplicates.
I am learning Prolog for an university exam using SWI Prolog and I have the following exercise:
Write the duplicates predicate that starting from a ListWithDuplicates
list (a list that admit duplicates) build a ListWithoutduplicates
(that contain the same elements from the previous list but without
duplicates):
duplicates(ListWithDuplicates, ListWithoutduplicates).
I think that I have to solve it using the setof built in predicate because I have found this exercise in the section related to this argument and because setof create an ordered list without duplicates.
The problem is that I always use setof to put into an order list without duplicates some object represented by facts and I don't know how to work on a list...
I have try something like this (but is is wrong and I know it):
/* FACT (BASE CASE): If the ListWithDuplicates is empty it is TRUE that the
ListWithoutDuplicates is empty:
*/
duplicates([], []).
duplicates(ListWithDuplicates, ListWithoutDuplicates) :-
setof(_, ListWithDuplicates, ListWithoutDuplicates).
I have try to divide it in two case: a base case: the list withoud duplicated created starting by an empty list it is an empty lust and a rule related to the case in which the ListWithDuplicates is not empty, so ListWithoutDiplicares have to be the result of the setof on the list that admit duplicates...
I have no idea about solve this exercise using setof...is it possible?
setof(X, member(X,List), SortedList).
but this is just a round-about way of saying
sort(List, SortedList).
I have a problem I want a code Prolog for that I will generate new predicate with the predicate "assert" but I want to use the result of my predicate .
i have a predicate that counts the number of element of a list here is it
and I have to make a new predicate that will add me a new predicate using the predicate "assert" in my knowledge base calling to the predicate "creat_nbStation" who will use the 2 "assert" and "compte" for exemple i have creat_nbStation(L) and L is a Liste it will add me in my knowledge base a new predicate it's nb_Station(L,25) using assert predicate .
thank you for the help.
this is my predicate for counting the number of elements of a list and it worka perfectly
compte([],0).
compte([_|R],N) :- compte(R,N1), N is N1+1, N>0.
It is quite difficult to figure out what exactly you are looking for, but I must say it does look very much like homework assignment. Is this what you are looking for?
create_nbStation(L) :- compte(L, N), assert(nbStation(L, N)).