Can someone explain this Prolog code [closed] - list

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 years ago.
Improve this question
aminoseq(X) :-
aminoseq(X, []).
aminoseq([], X) :-
print(X).
aminoseq([A|B], X) :-
aminotodna(A, Y),
append(X, Y, Z),
aminoseq(B, Z).
This Prolog code allows the user to enter in a list and combines that list with a preset aminotodna list and displays both of the results. I don't understand which part does what... I'd like to know for future work.
Any help is appreciated.

In addition to what Daniel wrote (+1), I have the following two minor points:
remove the _to_ from relation names. Since a pure relation can be used in all directions, it does not make sense to use a name that implies a direction.
always consider using dcg when describing lists. They often make your code a lot easier to read since they require fewer arguments and variable names.
I therefore suggest:
amino_dna(gly) --> [g,g,g].
amino_dna(gly) --> [g,g,a].
% ...
amino_dna(lys) --> [a,a,g].
% ...
amino_dna(ser) --> [t,c,g].
amino_dna(pro) --> [c,c,c].
amino_sequence([]) --> [].
amino_sequence([Acid|Acids]) -->
amino_dna(Acid),
amino_sequence(Acids).
Sample query:
?- length(Ls, _), phrase(amino_sequence(As), Ls).
As = Ls, Ls = [] ;
As = [gly],
Ls = [g, g, g] ;
As = [gly],
Ls = [g, g, a] ;
As = [lys],
Ls = [a, a, g] ;
As = [ser],
Ls = [t, c, g] ;
etc.
Notice the use of length/2 for fair enumeration.

First off, aminoseq/1 invokes aminoseq/2, implying that the second argument to aminoseq/2 is some sort of state variable whose initial value is the empty list.
Next, aminoseq/2 is recursively processing the first argument, which is a list. When the list becomes empty (I assume it's a list of amino acids or something) it just prints the second argument. That's the first clause of aminoseq/2.
Next, the second clause of aminoseq/2. It tries to convert the amino acid A (the current first item in the first argument list) into something else (DNA, I guess) and calls it Y. Then it appends X (the current "state" argument) to Y giving Z, which it then recurs on with the remaining items in the list of arguments.
I don't know a lot about biology, but I can guess that what's intended to happen here is that you want to pass in a list of amino acids and get back a list of DNA bases. This is not a spectacularly efficient approach (in particular, I kind of hate that you print at the end of aminoseq/2) but it will do the task. I would recommend that you examine the output using trace/0 to see what Prolog is trying to do as you go.
What part is doing what? All of the real work is being done in aminotodna/2 which is the actual table that goes from amino acids to codons. The rest of this code is just managing the data structure, the lists.
I would approach the problem more like this:
amino_dna(gly, [g,g,g]).
amino_dna(gly, [g,g,a]).
% ...
amino_dna(lys, [a,a,g]).
% ...
amino_dna(ser, [t,c,g]).
amino_dna(pro, [c,c,c]).
amino_acid_dna_sequence([], []).
amino_acid_dna_sequence([Acid|Acids], [C1,C2,C3|DNA]) :-
amino_dna(Acid, [C1,C2,C3]),
amino_acid_dna_sequence(Acids, DNA).
I find this a bit more direct: less append/3 banging around and no intermingling of I/O with logical relationships. And it can be driven in both directions:
?- amino_acid_dna_sequence([lys,ser,pro], X).
X = [a, a, g, t, c, g, c, c, c].
?- amino_acid_dna_sequence([lys,gly,pro], X).
X = [a, a, g, g, g, g, c, c, c] ;
X = [a, a, g, g, g, a, c, c, c].
?- amino_acid_dna_sequence(Aminos, [a,a,g,t,c,g,c,c,c]).
Aminos = [lys, ser, pro] ;
false.

Related

How to look up a value inside a list in a predicate, in PROLOG

So far I've done my fair amount of research and I've tried different methods, however even after reading multiple stack overflow answers and even a PDF from Addison Wesley, I can't find the way to do it. Here is the code
use_module(library(func)).
% importing library "func"
scale([c, d, e, f, g, a, b]).
scale(c, major, [c, d, e, f, g, a, b]).
scale(c, minor, [c, d, e_b, f, g, a_b, b_b]).
%1st attempt
search(note, scale):- scale(note, scale).
%2nd attempt
scaleOf(note, type_scale):- scale(note, type_scale).
on(item,[item|rest]).
on(item,[disregardHead|tail]):-
scale(tail),
on(item, tail).
%3rd attempt
fatherOf(father,type, son):- scale(father, type, sons), search(son, type, sons).
search(son, type, []):- !, fail.
search(son, type, [son|l]):- !, true.
search(son, type, [c|l]):- search(son, type, l).
What am I attempting? Simple, something that can iterate through the predicate scale(c, [c, d, e, f, g, a, b]). But I can't get it right.
Edit: I have multiple predicates because someone else suggested creating a predicate that would differentiate one scale from the other. I thought I could cram it inside any algorithm but I guess PROLOG is not that lenient :p
You can do that with member/2 [swi-doc]. This can be used to search, unify with a member, or generate a list.
So you can search with:
search(Note, Scale, Item) :-
scale(Note, Scale, Items),
member(Item, Items).
It is important that Note, Scale, Item and Items start with an Uppercase, since identifiers with a lower case are constants or functors. Identifiers with an uppercase are variables.
This will thus unify Item with the items in the list, for the given sample data we for example obtain:
?- search(c, minor, Item).
Item = c ;
Item = d ;
Item = e_b ;
Item = f ;
Item = g ;
Item = a_b ;
Item = b_b.

Remove duplicate from a list but not returning two same results in SWI-Prolog?

duplicate([],[]).
duplicate([A|B],[A|B1]) :- not(member(A,B)), duplicate(B,B1).
duplicate([A|B],List) :- member(A,B), duplicate(B,List).
I wrote this predicate to remove duplicate from the list, but when I test it,
?- duplicate([a,b,c,a,d,c,b,a,e,f],N).
N = [d, c, b, a, e, f] ;
N = [d, c, b, a, e, f] ;
false.
Is there a way to just keep one result only, not two same results? (so it will only return one list).
Also, I am not allowed to use operators that modify the backtracking search, such as the cut operator !, the negation operators not, +, or the if-then-else operator with -> and ;
It would be grateful if someone could help me . :D
The actual reason for receiving more than one answer is the goal member(A,As). It produces multiple answers for duplicates in As.
?- member(a, [a,a]).
true
; true.
There are several ways out.
memberchk/2 or once/1
memberchk/2 is defined as
memberchk(X, Xs) :-
once(member(X, Xs)).
This removes alternate answers. But then, it may remove otherwise valid solutions too. Consider:
?- memberchk(X, [a,b]), b = X.
false.
?- b = X, memberchk(X, [a,b]), b = X.
b = X.
So memberchk/2 is sensitive to the precise instantiation, which makes it a very brittle, impure predicate.
But it has one good point: It sticks to just one answer for
?- memberchk(a, [a,a]).
true.
So what would be ideal is a definition that is both pure and sticking to the first element. Enter
memberd/2
memberd(X, [X|_Ys]).
memberd(X, [Y|Ys]) :-
dif(X, Y),
memberd(X, Ys).
In this definition, the recursive rule is only of relevance if the list element is different. Thus this rule will never apply to memberd(a, [a,a,a]).
Another problem in your definition is not(member(A,B)) which only behaves as intended, if A and B are sufficiently instantiated. Your definition fails for:
duplicate([a,X],[a,b]). although there is a solution: X = b.
Rather replace it by non_member/2.
Alternatively, in case you are interested in the most efficient solution, consider library(reif) available
for
SICStus and
SWI which leads to:
list_nub([], []).
list_nub([X|Xs], Ys0) :-
if_(memberd_t(X, Xs), Ys0 = Ys1, Ys0 = [X|Ys1]),
list_nub(Xs, Ys1).
Here's one way to remove all duplicates, not the most efficient but I think it's quite easy to understand the intention.
rm_duplicates(In, Out) :-
exclude(has_duplicate(In), In, Out).
has_duplicate(List, Case) :-
dif(I, J),
nth0(I, List, Case),
nth0(J, List, Case).
If you mean to make a list into a set:
list_to_set(List, Set).
It's documented: list_to_set/2

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

Prolog- Appending a list of lists

My database follows this format:
aminotodna (Amincoacid, [DNA sequence]).
Here are a few examples from the database:
aminotodna(a,[g,c,a]).
aminotodna(a,[g,c,c]).
aminotodna(a,[g,c,g]).
aminotodna(a,[g,c,t]).
aminotodna(c,[t,g,c]).
aminotodna(c,[t,g,t]).
aminotodna(d,[g,a,c]).
aminotodna(d,[g,a,t]).
aminotodna(e,[g,a,a]).
aminotodna(e,[g,a,g]).
aminotodna(f,[t,t,c]).
aminotodna(f,[t,t,t]).
Some aminoacids have multiple DNA sequences.
Here is my question, so in a given list of amino acids for example [d,c,e,f], how can I append their DNA sequences together and give all combinations, as some have more than one sequence.
If it was just two I could do it, it'd just be
listamino(X,Y) :-
aminotodna(X,L),
aminotodna(Y,M),
append(L,M,Z),
print(Z).
hitting ; gives all combinations.
I've tired doing it with a list, but this is my attempt, and it didnt work:
listamino([]).
listamino([H|T]) :-
aminotodna(H,L),
aminotodna(T,M),
append(L,M,X),
print(X).
listamino(T).
When describing lists with Prolog, always consider using DCG notation for convenience and clarity. For example, using a subset of your examples, I first use DCG rules to describe the correspondence (note that I am using a name that makes sense in all directions):
amino_dna(a) --> [g,c,a].
amino_dna(a) --> [g,c,c].
amino_dna(c) --> [t,g,c].
amino_dna(c) --> [t,g,t].
an then I again use DCG rules to describe the concatenation of such lists:
aminos([]) --> [].
aminos([A|As]) --> amino_dna(A), aminos(As).
Sample query:
?- phrase(aminos([a,c]), As).
As = [g, c, a, t, g, c] ;
As = [g, c, a, t, g, t] ;
As = [g, c, c, t, g, c] ;
etc.
No append/3, no additional variables, no additional arguments, no nonsense. Use dcg!
You need an extra parameter to keep track of the current combination:
; invoke a version of listamino which tracks the current combination of DNA sequences, which is initially empty
listamino(X) :-
listamino(X,[]).
; If there are no ore aminos, print the DNA seq list, and we're done
listamino([],X) :-
print(X).
; Otherwise, append the DNA for the first amino to our list, and process the rest of the mains
listamino([H|T],X) :-
aminotodna(H,L),
append(X,L,X2),
listamino(T,X2).

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.