I m studying Prolog and i see this code
foo([],[]).
foo([[A,_ ]|L], [A|P]) :-foo(L ,P).
The result say that this code take N element of list of list,
Ad example if we give this query:
?foo([[car],[house],[man]],X)
X= [c,h,m]
At first read i see that something wrong.
For me this code take the tail of list of list and the rest of first element of the list , so for me first expansion will be (trace)
foo([[house],[man]], ar)
foo([[man]], ouse)
foo([], an)
false.
I try to compile with swi-prolog and give this trace:
[trace] ?- trace,foo([[car],[house],[man]],X).
Call: (9) foo([[car], [house], [man]], _1016) ? creep
Fail: (9) foo([[car], [house], [man]], _1016) ? creep
false.
What are I wrong?
Obtaining the first elements
The pattern [A, _] in your clause is wrong, or at at least not generic enough. [A, _] unifies with a list that contains exactly two elements, but this will thus fail for lists with more than two elements, or with one elements, like you found out.
You need to use the [A|_] pattern: indeed a list where the head is A, and we are not interested in the rest (tail). like:
foo([],[]).
foo([[A|_]|L], [A|P]) :- foo(L, P).
That being said, you can simplify this, by implementing a predicate that takes the head of a list:
head([H|_], H).
and then make use of maplist/3 [swi-doc]:
foo(A, B) :-
maplist(head, A, B).
maplist will thus call head like head(Ai, Bi), with Ai and Bi elements of A and B respectively.
Obtaining a substring with the first character
but based on the sample output, this is not what you want: you also want to obtain the first "character" of the atom, we can do that by using string_chars/2 [swi-doc]:
head_first([A|_], C) :-
string_chars(A, [C|_]).
and then define foo/2 again with maplist/3 [swi-doc]:
foo(A, B) :-
maplist(head_first, A, B).
we then obtain:
?- foo([[car],[house],[man]], X).
X = [c, h, m].
Related
How do I implement in Prolog the predicate list_for_set(Xs, Cs) where Cs is a list that contains the same elements as Xs, in the order of its first occurrence, but whose number of occurrences is only 1. For example, the query
? - list_for_set([1, a, 3.3, a, 1.4], Cs).
it happens only for Cs = [1, a, 3,4]. The consultation
? - list_for_set ([1, a, 3,3, a, 1,4], [a, 1,3,4])
must fail.
The Cs list of the previous statement will be called a set list, that is, a list with only one occurrence of each element.
Ok, there is some trickery involved.
foofilter([],_,_-T) :- T=[]. % close difflist
foofilter([L|Ls],Seen,H-T) :-
member(L,Seen),
!,
foofilter(Ls,Seen,H-T).
foofilter([L|Ls],Seen,H-T) :-
\+member(L,Seen),
!,
T=[L|NewT],
foofilter(Ls,[L|Seen],H-NewT).
:-begin_tests(filter).
data([1, a, 3, 3, a, 1, 4]).
test(one) :- data(L),
DiffList=[[]|T]-T, % Assume [] is never in L
foofilter(L,[],DiffList),
DiffList=[_|Result]-_,
format("~q ==> ~q\n",[L,Result]),
Result = [1,a,3,4].
:-end_tests(filter).
rt :- run_tests(filter).
Run tests:
?- rt.
% PL-Unit: filter [1,a,3,3,a,1,4] ==> [1,a,3,4]
. done
% test passed
true.
Someone will probably come up with a one-liner.
I am a beginner in Prolog and I am stuck in a homework assignment. I have to build a predicate myReverse(XS,YS) where XS is the reverse list of YS. I have built some logic as follows:
myReverse([],[]).
myReverse([H],[H]).
myReverse([L|H],[H|T]) :- myReverse(L,T).
This kinda works, but the output is not quite what I want. Some examples:
myReverse(L,[]).
L = [] % ok, that's fine
myReverse(L,[a]).
L = [a] % still fine
myReverse(L,[a,b]).
L = [[b]|a] % expected [b,a]
myReverse(L,[a,b,c]).
L = [[[c]|b]|a] % expected [c,b,a]
...
Is there any way I can achieve the expected output without using a accumulator or third party implementations like append?
Edit: This question is NOT a duplicate of Reversing a List in Prolog because I do NOT want to use accumulator. Also, this question is much more about the output format of my given solution than the solution itself.
You've misunderstood the [H|T] notation, tracing through the example reverse(L, [a, b]) will reveal it.
The first unification:
rule: myReverse([L|H],[H|T]) :- myReverse(L,T).
unified: myReverse([L|a], [a|[b]]) :- myReverse(L, [b]).
At this point a is a single atom, not a list, the T in [H|T] needs to be a list for a list to be complete. [a, b, c] is syntactic sugar for .(a, .(b, .(c, []))).
Your second unification, and third unifications are:
second: myReverse([b], [b]).
going back: myReverse([[b]|a], [a|[b]]) :- myReverse([b], [b]).
which outputs as: myReverse([[b]|a], [a, b]).
Your output [[b]|a] is not a complete list because a was an atom, not a list, which is why it's not output as [[b], a].
To not use an accumulator you'll need to add elements to the list as you exit the recursion and go back through the stack frames, keeping in mind a when you're handling a list or an atom:
myReverse([], []). % base case
myReverse([Head|Tail], Reversed) :-
myReverse(Tail, TailReversed), % recursive call
add_to_tail(Head, TailReversed, Reversed). % Put Head onto the end
add_to_tail(X, [],[X]). % base case
add_to_tail(X, [H|T], [H|Out]) :-
add_to_tail(X, T, Out). % recursive call, work done on exit
It's more efficient to use an accumulator. Best of luck learning Prolog.
I am currently attempting to write a Prolog program which will add a given character to the end of a list. The list's I want to append are elements within a list. This is what I currently have.
extends(X, [], []).
extends(X, [[Head]|Lists], Y):-
append([X], [Head], Y),
extends(X, Lists, [Y]).
Here I'm attempting to concatenate X and Head, storing it in Y. However I want Y to be a list of lists, so when it repeats the process again the next concatenation will be stored also in Y. So at the end of the program Y would store the results of all the concatenations. I would want the result to look like as follows.
?- extends(a, [[b,c], [d,e,f], [x,y,z]], Y).
Y = [[b,c,a], [d,e,f,a], [x,y,z,a]].
Could anyone help me out with this?
You want to apply some operation to corresponding elements of two lists. That operation talks about lists itself. It's easy to get confused with the nested levels of lists, so let's try not to think in those terms. Instead, define first a predicate that does the extension of one list:
element_list_extended(Element, List, Extended) :-
append(List, [Element], Extended).
This behaves as follows, using cases from your example:
?- element_list_extended(a, [b, c], Extended).
Extended = [b, c, a].
?- element_list_extended(a, List, [x, y, z, a]).
List = [x, y, z] ;
false.
Looks good so far. All we need to do is to apply this operation to corresponding elements of two lists:
extends(_Element, [], []).
extends(Element, [Xs | Xss], [Ys | Yss]) :-
element_list_extended(Element, Xs, Ys),
extends(Element, Xss, Yss).
And this works:
?- extends(a, [[b,c], [d,e,f], [x,y,z]], Y).
Y = [[b, c, a], [d, e, f, a], [x, y, z, a]] ;
false.
The key to making it work was to decompose the problem into two parts and to solve those simpler parts separately.
Now, if we like, since the definition of element_list_extended/3 is a single clause containing a single goal, we might decide to do without it and inline its definition into extends/3:
extends(_Element, [], []).
extends(Element, [Xs | Xss], [Ys | Yss]) :-
append(Xs, [Element], Ys),
extends(Element, Xss, Yss).
As you can see, you were quite close! You just had some superfluous brackets because you got confused about list nesting. That's precisely where decomposing the problem helps.
(As the other answer said, SWI-Prolog has some useful libraries that allow you to express even this in even shorter code.)
extends(PostFix, ListIn, ListOut) :-
maplist({PostFix}/[In,Out]>>append(In,[PostFix],Out),ListIn, ListOut).
This is using library(yall) a maplist/3 and append/3.
d_edge(a, b, 5).
e_edge(a, c, 6).
f_edge(b, c, 8).
% I will have a list of rules for the graph point
% from source to destination with weight.
list2pair([T], [A,B], [(T,A,B)]).
list2pair([T1|Tt], [A1,A2|T], Result) :-
list2pair(Tt, [A1|T], R1),
append([(T1,A1,A2)], R1, Result).
I want to come up with the result like
[d_edge(a,b), f_edge(b,c)]
my 1st arg will be the list of names [d_edge,f_edge]
my 2nd arg will be the list of vertexes [a,b,c].
My current code generates [(d_edge,a,b),(f_edge,b,c)].
Whenever I try to update the predicate from (T1,A1,A2) to T1(,A1,A2)
I get an error saying that it is not valid predicate.
I understand why I am getting the error. But I couldn't find a way around it.
First things first: T1(,A1,A2) is syntactically incorrect.
Here's how you could proceed using the built-in predicate (=..)/2 (a.k.a. "univ"):
list2pair([T], [A1,A2], [X]) :-
X =.. [T,A1,A2].
list2pair([T1|Tt], [A1,A2|T], [X|Xs]) :-
X =.. [T1,A1,A2],
list2pair(Tt, [A2|T], Xs).
Sample query using SICStus Prolog 4.3.2:
| ?- list2pair([d_edge,f_edge], [a,b,c], Xs).
Xs = [d_edge(a,b),f_edge(b,c)] ? ; % expected result
no
Note that the above only "constructs" these compound terms—it does not ensure that suitable facts d_edge/3, f_edge/3 etc really do exist.
Given atom x, I am trying to split a list into one with atoms smaller than x and one with atoms equal to or greater than x.
For example)
%% split(d,[a,b,c,d,e,f],AtomSmall, AtomBig) should give me
%% AtomSmall = [a,b,c], AtomBig = [d,e,f]
Below is what I've tried so far. I get the concept.However my code includes the atom that is equivalent to x in AtomSmall list, not AtomBig, although I check the case with before predicate.
For example)
%% split(d,[a,b,c,d,e,f],AtomSmall, AtomBig) gives me
%% AtomSmall = [a,b,c,d], AtomBig = [e,f]
before(X,Y):-atom_codes(X,A),atom_codes(Y,B),small(A,B).
small([],[]).
small([H1|T1],[H2|T2]):-H1<H2.
small([H1|T1],[H2|T2]):-H1=:=H2,small(T1,T2).
split(X,[],[],[]).
split(X,[H1|T1],[H1|Small],Big):-before(H1,X),split(X,T1,Small,Big).
split(X,[H1|T1],Small,[H1|Big]):-not(before(H1,X)),split(X,T1,Small,Big).
Please help!
In SWI-Prolog, you can use partition/4 from library(lists) and the standard order comparison (#>)/2:
?- lists:partition(#>(d),[a,b,c,d,e,f],L,R).
L = [a, b, c],
R = [d, e, f].
Since the order of arguments in comparison is fixed passing the pivot in as first argument, a lambda expression (using library(yall), needs a recent version) can help to give a more intuitive reading:
?- partition([E]>>(E#<d),[a,b,c,d,e,f],L,R).
L = [a, b, c],
R = [d, e, f].
Anyway, your code could be patched like this:
split(_,[],[],[]).
split(X,[H1|T1],[H1|Small],Big):-H1#<X,split(X,T1,Small,Big).
split(X,[H1|T1],Small,[H1|Big]):- \+ H1#<X,split(X,T1,Small,Big).
?- split(d,[a,b,c,d,e,f],L,R).
L = [a, b, c],
R = [d, e, f] ;
false.
Your before/2 predicate succeeds if the arguments are lexicographically equivalent. For example, before(a, a) is true. That's because your 3rd clause allows equal values throughout the list until the base case finally succeeds with two empty lists.
In addition, something you haven't encountered yet evidently, is that before(X, Y) will fail if X and Y are different length atoms. For example, before(ab, abc) will fail. So your small/2 needs to take care of that case as well.
A refactoring of small/2 will fix that:
% 1st clause is fixed so unequal length atoms are handled properly
small([], _).
small([H1|_], [H2|_]) :- H1 < H2.
% 3rd clause is fixed so that equal atoms won't succeed here
small([H,H1|T1], [H,H2|T2]) :- small([H1|T1], [H2|T2]).
But... you don't need to go through all that with before/2. Prolog knows how to compare, in a sensible way, atoms (and general Prolog terms) using the #< and #> operators, as #CapelliC indicated in his answer. So your before/2 just becomes:
before(X, Y) :- X #< Y.
And you don't need small/2 at all. That's basically the second solution that #CapelliC showed in his answer.