Prolog predicate to multiply two lists (representing unary numbers) - list

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

Related

Reversing list in Prolog

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

Prolog routing between 2 points and making a list of it

I need a method that returns all the roads* used in a route between two points, here's the map I have:
Example, to point A to E, i need a list of roads used, like that:
route(a, e, R).
R = [1,5].
I'm having problems in marking the routes that i've already visited, and on top of that, register the number of the road used in a list.
So here's my code so far:
road(1,a,b).
road(2,a,d).
road(3,b,c).
road(4,c,d).
road(5,b,e).
road(6,c,f).
road(7,d,f).
road(8,e,f).
connected(A,B) :- road(_,A,B).
route(A, B, R) :- road(R, A, B), road(R, B, A).
route(A, B, [R2|R]) :- route(A, C, R2), route(C, B, R2).
Thanks for the help!
I did know the procedure, but i was finding difficult in appending the roads to the list, here's the final code:
road(1,a,b).
road(2,a,d).
road(3,b,c).
road(4,c,d).
road(5,b,e).
road(6,c,f).
road(7,d,f).
road(8,e,f).
route(X,Y,[R]) :- road(R,X,Y).
route(X,Y,[R1|R2]) :- road(R1,X,Z), route(Z,Y, R2).
Here's my desired output:
?- route(a,f,R).
R = [1, 3, 6] .
I was making a confusion in appending the list in the second definition of route, the examples helped me.
Thanks for the help!!
Your solution is still not resisting cycles in graph, here is once that keeps it in mind
route(A,A,R,R).
route(A,B,R,R2) :- road(Rx,A,C), \+ member(Rx,R) , route(C,B,[Rx|R],R2).
route(A,B,R) :- route(A,B,[],Rx), reverse(R,Rx).

Why does my Pradicate my_flatten/2 not flatten a nested list structure? (Prolog)

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.

flatten list by replacing comma with plus operator inside a list in prolog

I am working on a scenario in Prolog (eclipse) wherein I need a list structure to be reformatted.
I have a list of the form:
MyList = [a,b,c].
I was trying to see if I can flatten the list to a single element with all the commas replaced with the + operator.
So my result list would look like:
ResultList = [a+b+c]
which is a single element list. The length of the initial list is arbitrary.
I know prolog is not suited for such operations, but can this be done?
here it is, in standard Prolog. I think there should be no difference with Eclipse:
list_to_op([X,Y|T], [R]) :-
list_to_op(T, X+Y, R).
edit: bug noted by false
list_to_op([X], [X]).
list_to_op([X], R, R+X).
list_to_op([X|T], R, Q) :-
list_to_op(T, R+X, Q).
test:
?- list_to_op([a,b,c],X).
X = [a+b+c] .
The accumulator is required to give the appropriate associativity: the simpler and more intuitive definition
list_to_op1([X], X).
list_to_op1([X|R], X+T) :-
list_to_op1(R, T).
gives
?- list_to_op1([a,b,c],X).
X = a+ (b+c) .
If evaluation order is important, use list_to_op.
edit:
there is a bug: list_to_op([a,b],X) fails.
here the correction, as often happens, it's a simplification:
list_to_op([], R, R).
list_to_op([X|T], R, Q) :-
list_to_op(T, R+X, Q).
This may help
flatten_list(A,[B]) :- flatten_list_inner(A,B).
flatten_list_inner([A],A).
flatten_list_inner([H|T],H+Y) :- flatten_list_inner(T,Y).
The output is slightly different from what you wanted. It is currently [a + (b + c)]
How about this non-recursive version..
list_to_op(L, Res) :-
concat_atom(L, '+', Atom),
Res = [Atom].
?- list_to_op([a,b,c], X).
X = ['a+b+c'].
Edit: This works in Swi-prolog.. not sure about Eclipse.

Custom reverse of a list in Prolog

I am trying to write a predicate that given the following list in Prolog:
[[1,a,b],[2,c,d],[[3,e,f],[4,g,h],[5,i,j]],[6,k,l]]
will produce the following list:
[[6,k,l],[[5,i,j],[4,g,h],[3,e,f]],[2,c,d],[1,a,b]]
As you can see I would like to preserve the order of the elements at the lowest level, to produce elements in the order 1, a, b and NOT b, a, 1.
I would also like to preserve the depth of the lists, that is, lists that are originally nested are returned as such, but in reverse order.
I have managed to achieve the desired order with the following code, but the depth is lost, i.e. lists are no longer nested correctly:
accRev([F,S,T],A,R) :- F \= [_|_], S \= [_|_], T \= [_|_],
accRev([],[[F,S,T]|A],R).
accRev([H|T],A,R) :- accRev(H,[],R1), accRev(T,[],R2), append(R2,R1,R).
accRev([],A,A).
rev(A,B) :- accRev(A,[],B).
I would appreciate help in correcting the code to preserve the correct nesting of lists. Thanks!
Two suggestions. First, here's one (rev_lists/2) which uses a bunch of SWI-PROLOG built-ins:
rev_lists(L, RL) :-
forall(member(M, L), is_list(M)), !,
maplist(rev_lists, L, L0),
reverse(L0, RL).
rev_lists(L, L).
This one works by testing if all elements of a list L are themselves lists (M); if so, it will recursively apply itself (via maplist) over all individual sub-lists, else it will return the same list. This has the required effect.
Secondly, here's rev_lists/2 again, but written such that it doesn't rely on built-ins except member/2 (which is common):
rev_lists(L, RL) :-
reversible_list(L), !,
rev_lists(L, [], RL).
rev_lists(L, L).
rev_lists([], Acc, Acc).
rev_lists([L|Ls], Acc, R) :-
( rev_lists(L, RL), !
; RL = L
),
rev_lists(Ls, [RL|Acc], R).
reversible_list(L) :-
is_a_list(L),
\+ (
member(M, L),
\+ is_a_list(M)
).
is_a_list([]).
is_a_list([_|_]).
It's basically the same strategy, but uses an accumulator to build up reverse lists at each level, iff they are comprised exclusively of lists; otherwise, the same list is returned.