I am attempting to get my arms around some basic prolog but struggling a bit in the process. In specific - I am trying to get through a list of items and copy it, item by item into a new list. I can get it to reverse, but I am finding it trickier doing it without reversing.
Ive been trying the following -
copy(L,R) :- accCp(L,R).
accCp([],R).
accCp([H|T],R) :- accCp(T,H).
When i run a trace on this - i can see the individual items being copied across, but they get 'lost', and dont form a growing list (at R, as i was hoping). How could i achivie this?
Many thanks
Your base case needs to set the copy list to empty when the original list is empty. Then, the recursive case needs to take H from list L and add it to the head of list R:
copy(L,R) :- accCp(L,R).
accCp([],[]).
accCp([H|T1],[H|T2]) :- accCp(T1,T2).
When you call copy, it works its way down to the base case, where it sets R to an empty list. Then, as it works back up, it keeps appending the head H of known list [H|T1] to the beginning of variable list [H|T2]. It does that until the original case is reached, at which point R contains a full copy of L.
Very simple approach would be:
clone1(X,X).
?-clone1([1,2,3],Z).
Z=[1,2,3]
Here's an expressive approach for the list handling. You want to copy or clone a list. My approach is add every element from the list to want to copy to another list and return another list.
clone([],[]).
clone([H|T],[H|Z]):- clone(T,Z).
OUTPUT
?- clone([1,2,3,4,5],Z).
Z=[1,2,3,4,5]
?- clone([a,b,c,d],Z).
Z=[a,b,c,d]
?- clone([ [a,1,2] , [b,2,3] , [c,3,4] ],Z).
Z = [[a, 1, 2], [b, 2, 3], [c, 3, 4]]
This works for every kind of list.
Related
I've found something about this in other questions, but mine is a bit different.
Given a string, I have to output another string with no adjacent duplicates.
E.g., given [a,a,b,b,c,d,a], my output will be [a,b,c,d,a].
Now, I've wrote the following recursive program to check if a certain given string has adjacent duplicates:
notequal(A,[]).
notequal(A,[X|S]) :- not(A=X).
noadj([]):-!.
noadj([A|S]) :- notequal(A,S), noadj(S).
How would I modify it in order to output what I described? I've tried multiple times but I'm new to prolog and I can't seem to get into its logic.
Of course, I'll need another variable, which would contain an element if notequal is true for that element.
So my idea is to iterate through the list and only add a certain term to the result if it passes the "notequal" test.
I'll edit this: I finally managed to do something like that by adding
noadjlist([X|S],[X|LS]) :- notequal(X,S), noadjlist(S,LS).
noadjlist([X|S],LS) :- noadjlist(S,LS).
noadjlist([],LS):-!.
However, my results are like:
?- noadjlist([1,2,2,3],LS).
LS = [1, 2, 3|_19316] .
why do I get that uninstantiated variable at the end?
noadjlist([],LS):-!.
should be
noadjlist([],[]):-!.
So I have a program that is supposed to replace every instance of an element in a list with another one but ONE BY ONE.
E.g.
change_element(5,[1,5,9,12,5,6],3,X). should give
X = [1,3,9,12,5,6] and
X = [1,5,9,12,3,6]
So it's replacing first 5 with 3, then in the second output, the first 5 remains 5 and the second changes to 3.
I was able to implement the code to change the first element but the code terminates after that. Doesn't goes to the second element.
change_element(A,[A|As],B,[B|As]).
change_element(A,[E|As],B,[E|Bs]):-
dif(A, E),
change_element(A,As,B,Bs).
Any idea, what should I do differently to get the desired result?
just go on after a match, preserving the old element:
change_element(A,[A|As],B,[B|As]).
change_element(A,[A|As],B,[A|Bs]):-
change_element(A,As,B,Bs).
change_element(A,[E|As],B,[E|Bs]):-
dif(A, E),
change_element(A,As,B,Bs).
I have a relation grandpa(X,Y) and I'm trying to get list of all grandpa's in the known world without using forall, findall and similar methods
My attempt so far is:
find_grandpas(Tmp,List):-
grandpa(New,_),
not(member(New,Tmp)),
find_grandpas([New|Tmp],List).
list_grandpas(List) :- find_grandpas([], List), print_list(List).
while checking stepswith trace I can see, that correct list is evaluated, but later it is lost. How can I construct some "cut" condition?
The problem here is that you build the right list but you need to tell where to stop. For example if we have as facts:
grandpa(a,_).
grandpa(b,_).
grandpa(c,_).
Eventually you will build list [a, b, c] and recursively try to find another solution there calling in the next iteration:
grandpa(New,_) will produce a but due to not(member(New,Tmp))this will fail, via backtracking it will try again with b... and c wher also fails. Then no choice points left and it completely fails. Soyou need to change to:
find_grandpas(Tmp,List):-
(
grandpa(New,_),
not(member(New,Tmp)) ->
find_grandpas([New|Tmp],List); List = Tmp
).
This simply says try grandpa(New,_),not(member(New,Tmp)) if succeed I have something to add, add it and go on in recursion. If not then no more solutions so set List = Tmp and this succeeds returning the right list.
Example:
?- find_grandpas([],L).
L = [c, b, a].
In my project I need to build a list of possible moves. I've already done that, but I need to filter the possible moves from previous moves. How can I do that?
From:
PossibleMoves = [(up,1,2),(down,2,4),(left,1,3)],
PreviousMoves = [(up,1,2),(down,2,4)].
To:
PossibleMovesLeft = [(left,1,3)].
I tried delete, \+ memberchk, without success. Maybe I did something wrong.
This question is not really related to mazes, it's just about removing all elements in a list from another list. There's a predicate for that: subtract/3.
subtract(+Set, +Delete, -Result)
Delete all elements in Delete from Set. Deletion is based on unification using memberchk/2.
Example usage:
?- subtract([1,2,5,4,3,5,4], [6,2,4], X).
X = [1, 5, 3, 5]
But if needed, it's really easy to roll your own version.
I want to add a element to a list and replace it with my list.
So i wrote
initialstate(0,[],[[1,0],[2,3],[1,2],[1,3]]).
add(X,L2,[X|L2]).
I would like to make something like that...
?- initialstate(_,List,_),add(4,List,List)
and replace me the initialstate to this one
initial_state(0,[4],[[1,0],[2,3],[1,2],[1,3]]).
The maining question for me it's how to replace the list inside the indetifiers "initialstate".
I am new in prolog...Please help me... and sorry if it is something stupid.
once provided the appropriate declaration
:- dynamic initialstate/3.
you could update your DB in this way
?- retract(initialstate(A,B,C)), assertz(initialstate(A,[4|B],C)).
If you want to change a list you get a different list. So you need a different name for it.
Prolog is not an imperative language but more a descriptive one. This means: you do not say do this and this. You say this is like that and when this is the case this is true/false in files (knowledge). Then you start the interpreter, consult the knowledge and ask questions wether something is true.
Writing A = B means that A is always B.
?- initialstate(_,List,_),add(4,List,List)
means initialstate of a List is when 4 added to the list is the list itself.
This is not true. if 4 is added there should be a 4 where no 4 was before.
You can do this:
append4(List, ListWithFourInside) :- append(List, [4], ListWithFourInside).
Which reads like when I append 4 to a list I get a list with 4 inside.
It can be done shorter if you want the 4 in the beginning
add4(List, ListWithFourInside) :- [4 | List] = ListWithFourInside.
or even shorter:
add4(List, [4|List]).