I'm new to Prolog and I have this code. I would like it to split a list into two lists or sublists where the first sublist/ list is of a predefined length and the other one contains the rest of the elements. Here's the code.
`
list_length([],0).
list_length([_|T],N):- list_length(T, N1), N is N1 + 1.
div(L, A, B, N) :-
append(A, B, L),
length(A, N),
length(B, N).
div(L, A, B, N) :-
append(A, B, L),
length(A, N),
N1 is N + 1,
length(B, N1).
div(L, A, B, N) :-
append(A, B, L),
length(A, N),
N1 is N - 1,
length(B, N1).
``
When I run my above code, it returns an error saying:
ERROR: Unknown procedure: (div)/4
ERROR: However, there are definitions for:
ERROR: (div)/3
false.
I would like the input to be this:
`?- div([44,55,23,86,49,94,30,77], L1, L2, 6).
L1 = [44,55,23,86,49,94]
L2 = [30,77]
Help me understand what I am doing wrong.
Help me understand what I am doing wrong.
You should be using length/2 and append/3, one after the other, like this:
div(L, A, B, N) :-
append(A, B, L),
length(A, N).
This is all.
Do not define your own length/2.
But you have not shown how you compile and evaluate your code. For example, I get:
?- [user].
|: div(L, A, B, N) :- append(A, B, L), length(A, N).
|: ^D% user://1 compiled 0.01 sec, 1 clauses
true.
?- div([a,b,c,d], A, B, 2).
A = [a, b],
B = [c, d] ;
false.
?- div([a,b,c,d], [X,Y], B, N).
X = a,
Y = b,
B = [c, d],
N = 2.
?- div([a,b,c,d], A, [X,Y,Z], N).
A = [a],
X = b,
Y = c,
Z = d,
N = 1 ;
false.
?- div([a,b], A, B, N).
A = [],
B = [a, b],
N = 0 ;
A = [a],
B = [b],
N = 1 ;
A = [a, b],
B = [],
N = 2 ;
false.
?- div(L, A, B, N).
L = B,
A = [],
N = 0 ;
L = [_A|B],
A = [_A],
N = 1 ;
L = [_A, _B|B],
A = [_A, _B],
N = 2 .
Since I made that mistake already, it is worth asking: Can you switch the order of append and length in the definition? What happens if you do?
I'm doing an exercise in Prolog and I'm stuck.
I need to swap three adjacent items in a list with another three elements.
That is:
| ?- swap([c,g,g,a,t,t,g,c,a,a], X).
X = [a,t,t,c,g,g,g,c,a,a]
X = [g,c,a,a,t,t,c,g,g,a]
X = [c,g,g,g,c,a,a,t,t,a]
X = [c,a,a,a,t,t,g,c,g,g]
.
.
.
This is what I have so far:
swap([H1, H2, H3, H4, H5, H6|T1], X) :-
X = [H4, H5, H6, H1, H2, H3|T1];
swap([H2, H3, H4, H5, H6|T1], X);
swap([H1, H2, H3, H4, H5|T1], X).
And the output for this is:
| ?- swap([c,g,g,a,t,t,g,c,a,a], X).
X = [a, t, t, c, g, g, g, c, a, a] ;
X = [t, t, g, g, g, a, c, a, a] ;
X = [t, g, c, g, a, t, a, a] ;
X = [g, c, a, a, t, t, a] ;
X = [c, a, a, t, t, g] ;
X = [c, a, a, a, t, t] ;
X = [g, c, a, g, a, t, a] ;
X = [c, a, a, a, t, g] ;
X = [c, a, a, g, a, t] ;
X = [t, g, c, g, g, a, a, a] ;
X = [g, c, a, g, a, t, a] ;
X = [c, a, a, a, t, g] ;
X = [c, a, a, g, a, t] ;
X = [g, c, a, g, g, a, a] ;
X = [c, a, a, g, a, g] ;
X = [c, a, a, g, g, a] ;
X = [t, t, g, c, g, g, c, a, a] ;
X = [t, g, c, g, g, t, a, a] ;
X = [g, c, a, g, t, t, a] ;
X = [c, a, a, t, t, g] ;
X = [c, a, a, g, t, t] ;
X = [g, c, a, g, g, t, a] ;
X = [c, a, a, g, t, g] ;
X = [c, a, a, g, g, t] ;
X = [t, g, c, c, g, g, a, a] ;
X = [g, c, a, g, g, t, a] ;
X = [c, a, a, g, t, g] ;
X = [c, a, a, g, g, t] ;
X = [g, c, a, c, g, g, a] ;
X = [c, a, a, g, g, g] ;
X = [c, a, a, c, g, g] ;
false.
The only problem that I have is that with every recursion I lose some part of the list and I don't know how to put it back.
It seems you are interested in describing RNA-sequences. Triples, that sounds much like anticodons. To make those sequences more readable, use:
:- set_prolog_flag(double_quotes, chars).
which permits you to write "attac" in place of [a,t,t,a,c]. See this how to get also compact answers.
Now for the swap. The easiest way is to first sketch what you want:
... Triple1 ... Triple2 ... is the OldSequence
... Triple2 ... Triple1 ... is the NewSequence
Where the ... are the same for both sequences. All of this can be readily translated using DCGs.
tripleswap(OldSequence, NewSequence) :-
dif(T1,T2),
phrase( ( seq(A), triple(T1), seq(B), triple(T2), seq(C) ), OldSequence),
phrase( ( seq(A), triple(T2), seq(B), triple(T1), seq(C) ), NewSequence).
seq([]) --> [].
seq([B|Bs]) --> [B], seq(Bs).
triple([A,B,C]) --> [A,B,C].
Whenever you distrust a DCG-definition, just try it out with phrase/2. Like
?- phrase(triple(T1), Bs).
T1 = Bs, Bs = [_A,_B,_C].
The non-terminal triple//1 describes a sequence of 3 elements (presumably nucleotides).
seq//1 is an arbitrarily long sequence.
There are solutions with better termination conditions, but they are less readable and often require certain assumptions that are difficult to maintain in the general case. Here is such a simple improvement:
samelength([], []).
samelength([_|Xs], [_|Ys]) :-
samelength(Xs, Ys).
and add samelength(OldSequence, NewSeqence) as the first goal. Now, tripleswap/2 terminates iff samelength/2 terminates. So one of the arguments should be a list of fixed length.
Also note that I think that "cccccc" has no swap. That's why I added dif(T1,T2).
?- tripleswap("cggattgcaa", Bs).
Bs = "attcgggcaa"
; Bs = "ttgacggcaa"
; Bs = "tgcatcggaa"
; Bs = "gcaattcgga"
; Bs = "caaattgcgg"
; Bs = "cttgggacaa"
; Bs = "ctgctggaaa"
; Bs = "cgcattggaa"
; Bs = "ccaattggga"
; Bs = "cgtgcgataa"
; Bs = "cggcatgata"
; Bs = "cgcaatggat"
; Bs = "cgggcaatta"
; Bs = "cggcaagatt"
; Bs = "cggacaattg"
; false.
BTW, dcgs are used in Molecular Biology since the 1980s. Start with
David B. Searls, Investigating the Linguistics of DNA with Definite Clause Grammars, NACLP 1989
and other work by the same author as well as Ross Overbeek around that time. All of this happened in the dawn of the Human Genome Project.
Basically this can be split into two subproblems:
first take a sequence of three elements; and
take another sequence of three elements and produce a list where we swapped these.
We can thus implement the two problems as follows:
swap(L, X) :-
swap1(L, S1, S2, T, X, Q),
swap2(T, S1, S2, Q).
where L is the list where we need to perform the swaps, X the list that is unified with the results, S1 and S2 the sequences that we select to swap, T the remaining elements after the first selection, and Q the part after the second sequence of the list to swap.
The first swap1 can thus be implemented as:
swap1([A1, A2, A3|T], [A1, A2, A3], [B1, B2, B3], T, [B1, B2, B3|Q], Q).
swap1([A1|T], A, B, R, [A1|Rest], S) :-
swap1(T, A, B, R, Rest, S).
For the given sample list, this will thus yield:
?- swap1([c,g,g,a,t,t,g,c,a,a], A, [B1, B2, B3], T, X, R).
A = [c, g, g],
T = [a, t, t, g, c, a, a],
X = [B1, B2, B3|R] ;
A = [g, g, a],
T = [t, t, g, c, a, a],
X = [c, B1, B2, B3|R] ;
A = [g, a, t],
T = [t, g, c, a, a],
X = [c, g, B1, B2, B3|R] ;
A = [a, t, t],
T = [g, c, a, a],
X = [c, g, g, B1, B2, B3|R] ;
A = [t, t, g],
T = [c, a, a],
X = [c, g, g, a, B1, B2, B3|R] ;
A = [t, g, c],
T = [a, a],
X = [c, g, g, a, t, B1, B2, B3|R] ;
A = [g, c, a],
T = [a],
X = [c, g, g, a, t, t, B1, B2, B3|...] ;
A = [c, a, a],
T = [],
X = [c, g, g, a, t, t, g, B1, B2|...] ;
false.
Here it thus proposes eight ways to pick three adjacent sequences that can be used to swap.
Then the second swap need to find three adjacent elements in the remaining lists to swap, and put the ones that have been picked by swap1/6 at the places where it picks elements from, like:
swap2([B1,B2,B3|R], [A1,A2,A3], [B1, B2, B3], [A1,A2,A3|R]).
swap2([B1|R], As, Bs, [B1|T]) :-
swap2(R, As, Bs, T).
For the given sample data, this thus gives us:
?- swap([c,g,g,a,t,t,g,c,a,a], X).
X = [a, t, t, c, g, g, g, c, a, a] ;
X = [t, t, g, a, c, g, g, c, a, a] ;
X = [t, g, c, a, t, c, g, g, a, a] ;
X = [g, c, a, a, t, t, c, g, g, a] ;
X = [c, a, a, a, t, t, g, c, g, g] ;
X = [c, t, t, g, g, g, a, c, a, a] ;
X = [c, t, g, c, t, g, g, a, a, a] ;
X = [c, g, c, a, t, t, g, g, a, a] ;
X = [c, c, a, a, t, t, g, g, g, a] ;
X = [c, g, t, g, c, g, a, t, a, a] ;
X = [c, g, g, c, a, t, g, a, t, a] ;
X = [c, g, c, a, a, t, g, g, a, t] ;
X = [c, g, g, g, c, a, a, t, t, a] ;
X = [c, g, g, c, a, a, g, a, t, t] ;
X = [c, g, g, a, c, a, a, t, t, g] ;
false.
Here the places that are swapped are written in boldface.
I think permutation/2 will help:
swap(Es,Sw) :- triples(Es,Ts),permutation(Ts,Sw0),append(Sw0,Sw).
triples([A,B,C|Es],[[A,B,C]|Ts]) :- !, triples(Es,Ts).
triples([],[]) :- !.
triples(R,[R]).
yields
?- swap([c,g,g, a,t,t, g,c,a], X).
X = [c, g, g, a, t, t, g, c, a] ;
X = [c, g, g, g, c, a, a, t, t] ;
X = [a, t, t, c, g, g, g, c, a] ;
X = [a, t, t, g, c, a, c, g, g] ;
X = [g, c, a, c, g, g, a, t, t] ;
X = [g, c, a, a, t, t, c, g, g] ;
false.
note: triples/2 allows for not triple data in tail, but you can drop this (maybe unwanted) feature just deleting the last clause:
triples(R,[R]). % drop this
Then the cuts become useless, just drop drop them:
triples([],[]). % just for style in this case, move to first clause
triples([A,B,C|Es],[[A,B,C]|Ts]) :- triples(Es,Ts).
I have a list of tuples:
L = [{1, [a, b, c]}, {2, [d, e, f]}, {3, [[h, i, j], [k, l, m]]}]
this is what I have
lists:map(fun({_, B}-> B end, L).
the output is
[[a, b, c], [d, e, f], [[h, i, j], [k, l, m]]]
what I want is:
[[a, b, c], [d, e, f], [h, i, j], [k, l, m]]
it seems a pretty easy problem, but I can't figure out how to do it.
Please help!
Let's see...
1> L = [{1, [a, b, c]}, {2, [d, e, f]}, {3, [[h, i, j], [k, l, m]]}].
[{1,[a,b,c]},{2,[d,e,f]},{3,[[h,i,j],[k,l,m]]}]
Trivial and straightforward, but not tail-recursive:
2> lists:foldr(fun ({_,[X|_]=E},A) when is_list(X) -> lists:append(A,E);
({_,E},A) -> [E|A] end,
[], L).
[[a,b,c],[d,e,f],[h,i,j],[k,l,m]]
Not being tail-recursive is not very nice, though, but...
3> lists:reverse(lists:foldl(fun ({_,[X|_]=E},A) when is_list(X) ->
lists:reverse(E,A);
({_,E},A) -> [E|A] end,
[], L)).
[[a,b,c],[d,e,f],[h,i,j],[k,l,m]]
...the tail-recursive version also works (thanks to Zed for pointing out lists:reverse/2).
For your specific example case, you can define the following function:
group3([], Acc) ->
Acc;
group3([A,B,C|Tl], Acc) ->
group3(Tl, [[A,B,C]] ++ Acc).
group3(L) ->
lists:reverse(group3(L, [])).
and invoke it like this:
group3(lists:flatten(lists:map(fun({_, B}) -> B end, L))).
Hopefully that's enough to give you a general strategy.
-module(z).
-export([do/1]).
do([{_,[X|_] = L}|Tl]) when is_list(X) -> L ++ do(Tl);
do([{_, L} |Tl]) -> [L|do(Tl)];
do([]) -> [].
test:
1> z:do(L).
[[a,b,c],[d,e,f],[h,i,j],[k,l,m]]