I am starting with prolog, and as an exercise I am trying to reverse a list.
For example, inv([1,2,3], S) should give S = [3,2,1].
Below is what a partner and I have already done:
conc([], L, L).
conc([X|L1], L2, [X|L3]) :- conc(L1, L2, L3).
tail([X|Y], S) :- conc([], Y, S).
inv([X|Y], S) :- tail([X|Y], TAIL), inv(TAIL, R_TAIL), conc(R_TAIL, X, S).
inv([], []).
The first three lines work fine. But really don't understand what's going on with the last two, and therefore how to fix it.
I just wanna find the tail (this is working, when I just use the tail function) of the list, reverse it and then append it to the head of the list.
Could you help me guys?
Alternative foldl/4 based solution:
prepend_element(E, L, [E|L]).
inv(List, Reversed) :-
foldl(prepend_element, List, [], Reversed).
Your code doesn't work for me.
Try this way instead:
?- reverse([1,2,3],Xs), write(Xs).
reverse(Xs,Ys) :- reverse(Xs,[],Ys).
reverse([],A,A).
reverse([H|T],R,A) :- reverse(T,[H|R],A).
Related
I want to write a code that multiplies lists representing a number, like:
?- times([1,1,1], [1,1], Res).
Res = [1,1,1,1,1,1].
times([], _, []). % base case
times([_|T], Lis, [Lis|H]) :-
times(T, Lis, H).
I already have the code above and it kinda does what I want but not really. For example when asking:
?- times([1,1,1], [1,1], Res)
Res = [[1,1],[1,1],[1,1]].
The idea is there, but I just don't know how to fix that, I understand why it's happening (I'm adding a list as head), so I just wondered if anybody could help me.
Thanks in advance.
[Lis|H] will use Lis as first element, regardless whether Lis is a list or not. You should take a look at append/3 [swi-doc] for example to append two lists:
times([], _, []).
times([_|T], Lis, R) :-
append(Lis, H, R),
times(T, Lis, H).
I'm trying to find duplicate (non unique) items in a list.
For example from
duplicate([a,b,c,a,b,r,d,c], R).
I need to get [a,b,c].
I've written so far prolog program that finds duplicate elements in a list.
However, I get the answer as single elements.
R = a
R = b
R = c
And I have to get them in a list as [a,b,c]
duplicate([First|Rest], Element) :-
duplicate_first(Rest, First, Element).
duplicate_first([Head|Rest], X, X) :-
duplicate_second(Rest, Head, X).
duplicate_first([Head|Rest], _, X) :-
duplicate_first(Rest, Head, X).
duplicate_second(_, X, X).
duplicate_second([Head|Rest], _, X) :-
duplicate_second(Rest, Head, X).
P.S. I don't want to use any swi-prolog build in functions.
I find it a bit of a straightjacket to ignore the standard library. But you can fulfill the requirement by implementing the two predicates you need, which are member/2 and delete/3, yourself:
my_member(X, [X|_]).
my_member(X, [_|Xs]) :- my_member(X, Xs).
This is probably the most straightforward way to implement member/2, although it isn't exactly the same as in the SWI library.
my_delete([], _, []).
my_delete([X|Xs], X, Ys) :- my_delete(Xs, X, Ys).
my_delete([Y|Xs], X, [Y|Ys]) :- X \= Y, my_delete(Xs, X, Ys).
I just sort of took a crack at this and it seems to be OK. A better implementation would probably use something like X = Y -> ... but that can lead to issues with backtracking so I am using this variation which probably has other problems.
Now that you have the preliminaries, the actual implementation is not that hard. First your base case. There are no duplicates in the empty list.
duplicates([], []).
Now you have two inductive cases. One, in which the head of the list occurs inside the tail of the list. When that happens you add it to the result and remove it from the tail (or you'll get duplicates in your list of duplicates).
duplicates([X|Xs], [X|Ys]) :-
my_member(X, Xs),
my_delete(Xs, X, XsWithoutX),
duplicates(XsWithoutX, Ys).
Your other case is when the head element does not appear in the tail, so you can simply recur and find the rest of the duplicates:
duplicates([X|Xs], Ys) :-
\+ my_member(X, Xs),
duplicates(Xs, Ys).
I'm a little out of practice so the following code can be simplified but... given a filter function (that remove the Val correspondences from a list and return [Val] if correspondence is found or empty list otherwise)
filter(_, [], [], []).
filter(Val, [Val | Rest], [Val], LR) :-
filter(Val, Rest, _, LR).
filter(Val1, [Val2 | Rest], LO, [Val2 | LR]) :-
Val1 \= Val2,
filter(Val1, Rest, LO, LR).
and given a sort of optional adder in front of a list
addOptional([], L, L).
addOptional([O], L, [O | L]).
I suppose you can write duplicate/2 as follows
duplicate([], []).
duplicate([First | Rest], Result) :-
filter(First, Rest, Opt, Filtered),
duplicate(Filtered, Res2),
addOptional(Opt, Res2, Result).
I'm trying to delete an item in a list. My code works but it doesn't delete the symbol in a nested list.
In the second to last rule I'm trying to check if the next element is a list. What am I doing wrong?
del(Symbol, [], []) :-
!.
del(Symbol, [Symbol|Tail], Result) :-
!,
del(Symbol, Tail, Result).
del(Symbol, [[List]|Tail], Result) :-
!,
del(Symbol, List, Result2),
append([List], Result2, Result).
del(Symbol, [Other|Tail], Result) :-
!,
del(Symbol, Tail, Result2),
append([Other], Result2, Result).
once you have a working del/3 on a flat list, you can extend it to handle nested lists, checking the type of the first element: if it's a list, recurse and keep the outcome.
To check the type, you can use is_list/1
The predicate i wrote flattens a simple list like List=[a,b,c,[d,e],f],
but not a list like List2 = [a,b,[[c,d],e],f]. Here is my code:
my_flatten([], []).
my_flatten([H|T], R):- not(is_list(H)), my_flatten(T, R1), append([H], R1, R).
my_flatten([H|T], R):- is_list(H), my_flatten(T, R1), append(H, R1, R).
My idea is to check whether the head is a list or not and depending on this decision to go through recursion and append the tail to the head.
Am I missing an important point?
Am I missing an important point?
yes, of course. Boris is right that you will learn more if you try to find the problem yourself. Just an hint: you must recurse on the head, when it's a list, to get it flattened.
After that (just add a call in proper place in last clause) and you'll get
?- my_flatten([a,b,[[c,d],e],f], L).
L = [a, b, c, d, e, f] ;
false.
I want to reverse each list from a list of lists.
I have something which looks like:
[[a,b],[],[c,d,e],[],[],[f,g]]
What I want is to read through the list of lists and reverse each list and get this result:
[[b,a],[],[e,d,c],[],[],[g,f]]
I already have a reverse function:
reverse(L, R) :- reverse(L, [], R).
reverse([], R, R).
reverse([H|T], A, R) :- reverse(T, [H|A], R).
How can I manage to read through the list?
Will a recursive function like this one work ?
reverseLL([H|T], L) :-
reverse(H,NH),
reverseLL([T],[NH|L]).
reverseLL([],L).
reverseInList([],[]).
reverseInList([H|Ts],[H1|R]):-
reverse(H,H1),
reverseInList(Ts,R).
This works by recursing over the list and using the library function 'reverse/2' to reverse each sublist.