Using tail recursion to duplicate items on a list - list

I have a homework problem that asks us to write a predicate that creates a duplicate of every item on a list, first using linear recursion and then using tail recursion. We can't use built-in predicates.
I could solve it using linear recursion, but I'm having a bit of trouble with the tail recursion.
This is what I tried:
dup_elem_tail([], Res, Res).
dup_elem_tail([P | R], Lst2, Aux) :- dup_elems_tail(R, Lst2, [P, P | Aux]).
If the input is dup_elem_tail([a, b, c], L). The output should be L = [a, a, b, b, c, c]. Instead, I got [c, c, b, b, a, a].
Now, I know where my mistake is. In
dup_elem_tail([P | R], Lst2, Aux) :- dup_elems_tail(R, Lst2, [P, P | Aux]).
I am 'putting' the two Ps on the left side of the list, when I should be putting them in the right side. However, I am not finding a way to do it.

You don't need to use an accumulator for this task. Simply construct the output list in the head:
dup_elems_tail([], []).
dup_elems_tail([P| Ps], [P, P | DPs]) :-
dup_elems_tail(Ps, DPs).
Sample call:
| ?- dup_elems_tail([a, b, c], L).
L = [a,a,b,b,c,c]
yes

Related

Prolog Lists from List Predicate

I am trying to make a code in which the input is a list with lists and non-lists within it and the output is a list with the lists from the first input. So, for example input listsFromList([2,3,6,[a,g],2,3,[c,d]],X). The output would be X = [[a,g],[c,d]]. I am trying to do it with an accumulator.
So I made this code:
listsFromList([],A) :- A.
listsFromList([H|SOURCEs],A) :-
is_list(H),
append([A],H,A),
listsFromList(SOURCEs,A).
listsFromList([H|SOURCEs],A) :-
\+ is_list(H),
listsFromList(SOURCEs,A).
It does not work if I put more than one list in the first list and also it gives a wrong output when I put one list in it. Can anyone help?
You need to modify few things. Here a solution with the same number of arguments:
listsFromList([],[]).
listsFromList([H|SOURCEs],[H|A1]) :-
is_list(H),
listsFromList(SOURCEs,A1).
listsFromList([H|SOURCEs],A) :-
\+ is_list(H),
listsFromList(SOURCEs,A).
?- listsFromList([2,3,6,[a,g],2,3,[c,d]],X).
X = [[a, g], [c, d]];
false
If you want to use append/3, you could add an accumulator list (so increase the arity form 2 to 3), but this is unnecessary, or swap the position of append/3. Furthermore, you can add a cut (!) to avoid the false solution.
Solution wiht accumulator:
listsFromList([],L,L).
listsFromList([H|SOURCEs],LIn,LO) :-
is_list(H),
append([H],LIn,L),
listsFromList(SOURCEs,L,LO).
listsFromList([H|SOURCEs],L,LO) :-
\+ is_list(H),
listsFromList(SOURCEs,L,LO).
?- listsFromList([2,3,6,[a,g],2,3,[c,d]],[],X).
X = [[c, d], [a, g]]
false
If you want to use append/2 with arity 2 of the main predicate, use:
listsFromList([],[]).
listsFromList([H|SOURCEs],L) :-
is_list(H),
listsFromList(SOURCEs,L1),
append([H],L1,L).
listsFromList([H|SOURCEs],A) :-
\+ is_list(H),
listsFromList(SOURCEs,A).
?- listsFromList([2,3,6,[a,g],2,3,[c,d]],X).
X = [[a, g], [c, d]]
false
If you want to be super fancy and super short, you can solve your problem (assuming you are running SWI Prolog) with one line:
?- include(is_list,[2,3,6,[a,g],2,3,[c,d]],X).
X = [[a, g], [c, d]]

Sublists of consecutive similar elements from a list in Prolog

I'm new to Prolog and trying to do this question. We have a list
List = [a,a,a,a,b,c,c,a,a,d,e,e,e,e]
I want to pack it into sub-lists of similar elements.
Pack( [a,a,a,a,b,c,c,a,a,d,e,e,e,e], Sublists)
should give
Sublists = [[a,a,a,a],[b],[c,c],[a,a],[d],[e,e,e,e]]
This is what I have tried so far:
pack([],[],[]).
pack([H],[H],[H]).
pack([H,H1|T],Z,X):- H==H1 , append([H],Z,Z1) , pack([H1|T],Z1,X).
pack([H,H1|T],Z,X):- H=\=H1 , append([H],Z,Z1) ,
append(Z1,X,Xs) , pack([H1|T],Z1,Xs).
Below is the error:
Arithmetic: `a/0' is not a function
In:
[4] a=\=b
[3] pack([a,b|...],[a,a],_1608) at line 13
[2] pack([a,a|...],[a],_1688) at line 13
[1] pack([a,a|...],[],_1762) at line 13
Thanks in advance. I'm trying to solve these problems:
P-99: Ninety-Nine Prolog Problems.
You can approach this kind of problem with simple list processing and using SWI Prolog's dif/2 to provide a general solution:
pack([], []). % packing empty is empty
pack([X], [[X]]). % packing a single element
pack([X,X|T], [[X|PH]|PT]):- % rule for packing when next two terms are the same
pack([X|T], [PH|PT]).
pack([X,Y|T], [[X]|PT]):- % rule for different term
dif(X, Y),
pack([Y|T], PT).
2 ?- pack([a,a,a,a,b,c,c,a,a,d,e,e], L).
L = [[a, a, a, a], [b], [c, c], [a, a], [d], [e, e]] ;
false.
3 ?- pack(L, [[a,a,a], [b,b], [c]]).
L = [a, a, a, b, b, c] ;
false.
4 ?-
Note that lurker's solution still has some performance issues. See the ; false for each solution? This is an indication that Prolog still retains some memory (called a choice point - actually there may be even several such choice points). For many cases however, no such choice point is needed. Here is a solution that overcomes that problem (The name group in place of pack is quite common in the context of Haskell)
group([], []).
group([E|Es], [[E|Gs]|Gss]) :-
igroup(Es, E, Gs, Gss).
igroup([], _, [], []).
igroup([E|Es], F, Gs1, Gss1) :-
( E\=F
-> Gs1=[], Gss1=[[E|Gs2]|Gss2]
; E==F
-> Gs1=[E|Gs2], Gss1=Gss2
; E=F,
Gs1=[E|Gs2], Gss1=Gss2
; dif(E, F),
Gs1=[], Gss1=[[E|Gs2]|Gss2]
),
igroup(Es, E, Gs2, Gss2).
Note how the testing for the equality of E and F is split into four cases:
First E \= F which means that both are definitely different.
Then E == F which means that both are definitely identical.
Then E = F which is the general case of equality, and
dif(E, F) which is the case of general inequality
For the last two cases there is no -> because both may be true.
Since it is quite cumbersome to maintain so many cases, there is library(reif)
for
SICStus and
SWI which permits to write the same more compactly:
igroup([], _, [], []).
igroup([E|Es], F, Gs1, Gss1) :-
if_(E = F
, ( Gs1 = [E|Gs2], Gss1 = Gss2 )
, ( Gs1 = [], Gss1 = [[E|Gs2]| Gss2] )),
igroup(Es, E, Gs2, Gss2).
The error you got is because =\=/2 is true if expr1 is evaluates to a number not equal to expr2 . Instead you can use \=\2 which evaluates \+term1=term2. ==/2 evaluates to term1 equivalent to term2, =:=/ is true if expr1 is a number which is equal to expr2. One more mistake I found in your code is you're not clearing the Intermediate List. You have to flush the values in it after you have added the similar elements list to your Sublists list. I have used cut ! to reduce backtracking. Instead, if you write mutually exclusive predicates, it's better.
I have edited your code:
pack1([],[],[]).
pack1([H],L,[Z]):- append([H],L,Z),!.
pack1([H,H1|T],Z,X):- H == H1 , append([H],Z,Z1) , pack1([H1|T],Z1,X),!.
pack1([H,H1|T],Z,[Z1|Zs]):- H\=H1 ,append([H],Z,Z1) ,pack1([H1|T],[],Zs),!.
Output:
?-pack1([a,a,a,a,b,c,c,a,a,d,e,e,e,e],[],Z).
Z=[[a, a, a, a], [b], [c, c], [a, a], [d], [e, e, e, e]]
?-pack1([a,a,a,a,b,c,1,c,a,a,d,e,e,e,e],[],Z).
Z= [[a, a, a, a], [b], [c], [1], [c], [a, a], [d], [e, e, e, e]]
?-pack1([],[],Z).
Z= []
Hope this helps.
without using dif/2
my_pack([],[[]]).
my_pack([X], [[X]]).
my_pack([X,X|L], [F|R]) :- my_pack([X|L], [F1|R]), append([X], F1, F).
my_pack([X|L], [F|R]) :- my_pack(L, R), append([X], [], F).

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 ,

Trimming off uninitialized list values in prolog

I'm writing something in prolog and the way I used append, it ends up returning a list like [a,b,c|_]. Is there any standard predicate (or simple way) to cut off all the uninitialized/arbitrary values?
Edit to add: Length won't work because the list could be of an arbitrary length, I don't know what it's going to be ahead of time, otherwise I would have already used that to trim it.
You should check into why append is giving you a list like that. Because observe this behavior of append that fixes the problem you are seeing:
?- append([a,b,c|_], X, L).
L = [a,b,c|X]
?- append([a,b,c|_], X, L), X=[].
L = [a,b,c]
If you're list isn't terminated with [], you're almost certainly building your list incorrectly.
You can use length/2 to this end!
?- Xs = [1,2,3|_], length(Xs, N).
Xs = [1,2,3], N = 3
; Xs = [1,2,3,_A], N = 4
; Xs = [1,2,3,_A,_B], N = 5
; ... .
However, it is not clear to me what you want to describe here. If you want to stick with the smallest solution use once(length(Xs, N)) instead.
You can close an open list like this:
close_list([]) :- !.
close_list([_ | T]) :-
close_list(T).
i.e. you have to walk through all the elements to reach the variable tail, and then bind it to the empty list.
Usage:
?- List = [a, b, C, d, 2.2 | _], close_list(List).
List = [a, b, C, d, 2.2].
If you hold a variable that is bound to the tail then it becomes much simpler:
?- List = [a, b, C, d, 2.2 | Tail], Tail = [].
List = [a, b, C, d, 2.2],
Tail = [].