changing list of strings to atoms using maplist? - prolog

How to change string to atoms using maplist.
This does not work :
?- maplist(atom_string,["a","b","c"]).
first because atom_string/2 has arity of two (How do you do partial-function//currying in prolog).
But even if partial-fun worked the complication is that the first argument of atom_string is the unknown i.e. the call is :
atom_string(A,"atom")
not :
atom_string("atom",A)
this worked :
?- use_module(library(lambda)).
?- F = \Y^X^(atom_string(X,Y)), maplist(F,["a","b","c"],L).
F = \Y^X^atom_string(X, Y),
L = [a, b, c].

This works as intended:
?- maplist(atom_string, Atoms, ["a","b","c"]).
Atoms = [a, b, c].
If this is not what you are after, please explain.

Use a helper predicate.
string_atom(String,Atom) :-
atom_string(Atom,String).
Then run using
?- maplist(string_atom,["a","b","c"],Atoms).
Atoms = [a, b, c].

Related

Prolog Out of stack error

I'm working on Problem 26 from 99 Prolog Problems:
P26 (**) Generate the combinations of K distinct objects chosen from
the N elements of a list
Example:
?- combination(3,[a,b,c,d,e,f],L).
L = [a,b,c] ;
L = [a,b,d] ;
L = [a,b,e] ;
So my program is:
:- use_module(library(clpfd)).
combination(0, _, []).
combination(Tot, List, [H|T]) :-
length(List, Length), Tot in 1..Length,
append(Prefix, [H], Stem),
append(Stem, Suffix, List),
append(Prefix, Suffix, SubList),
SubTot #= Tot-1,
combination(SubTot, SubList, T).
My query result starts fine but then returns a Global out of stack error:
?- combination(3,[a,b,c,d,e,f],L).
L = [a, b, c] ;
L = [a, b, d] ;
L = [a, b, e] ;
L = [a, b, f] ;
Out of global stack
I can't understand why it works at first, but then hangs until it gives Out of global stack error. Happens on both SWISH and swi-prolog in the terminal.
if you try to input, at the console prompt, this line of your code, and ask for backtracking:
?- append(Prefix, [H], Stem).
Prefix = [],
Stem = [H] ;
Prefix = [_6442],
Stem = [_6442, H] ;
Prefix = [_6442, _6454],
Stem = [_6442, _6454, H] ;
...
maybe you have a clue about the (main) problem. All 3 vars are free, then Prolog keeps on generating longer and longer lists on backtracking. As Boris already suggested, you should keep your program far simpler... for instance
combination(0, _, []).
combination(Tot, List, [H|T]) :-
Tot #> 0,
select(H, List, SubList),
SubTot #= Tot-1,
combination(SubTot, SubList, T).
that yields
?- aggregate(count,L^combination(3,[a,b,c,d,e],L),N).
N = 60.
IMHO, library(clpfd) isn't going to make your life simpler while you're moving your first steps into Prolog. Modelling and debugging plain Prolog is already difficult with the basic constructs available, and CLP(FD) is an advanced feature...
I can't understand why it works at first, but then hangs until it gives Out of global stack error.
The answers Prolog produces for a specific query are shown incrementally. That is, the actual answers are produced lazily on demand. First, there were some answers you expected, then a loop was encountered. To be sure that a query terminates completely you have to go through all of them, hitting SPACE/or ; all the time. But there is a simpler way:
Simply add false at the end of your query. Now, all the answers are suppressed:
?- combination(3,[a,b,c,d,e,f],L), false.
ERROR: Out of global stack
By adding further false goals into your program, you can localize the actual culprit. See below all my attempts: I started with the first attempt, and then added further false until I found a terminating fragment (failure-slice).
combination(0, _, []) :- false. % 1st
combination(Tot, List, [H|T]) :-
length(List, Length), Tot in 1..Length, % 4th terminating
append(Prefix, [H], Stem), false, % 3rd loops
append(Stem, Suffix, List), false, % 2nd loops
append(Prefix, Suffix, SubList),
SubTot #= Tot-1, false, % 1st loops
combination(SubTot, SubList, T).
To remove the problem with non-termination you have to modify something in the remaining visible part. Evidently, both Prefix and Stem occur here for the first time.
The use of library(clpfd) in this case is very suspicious. After length(List, Length), Length is definitely bound to a non-negative integer, so why the constraint? And your Tot in 1..Length is weird, too, since you keep on making a new constrained variable in every step of the recursion, and you try to unify it with 0. I am not sure I understand your logic overall :-(
If I understand what the exercise is asking for, I would suggest the following somewhat simpler approach. First, make sure your K is not larger than the total number of elements. Then, just pick one element at a time until you have enough. It could go something like this:
k_comb(K, L, C) :-
length(L, N),
length(C, K),
K =< N,
k_comb_1(C, L).
k_comb_1([], _).
k_comb_1([X|Xs], L) :-
select(X, L, L0),
k_comb_1(Xs, L0).
The important message here is that it is the list itself that defines the recursion, and you really don't need a counter, let alone one with constraints on it.
select/3 is a textbook predicate, I guess you should find it in standard libraries too; anyway, see here for an implementation.
This does the following:
?- k_comb(2, [a,b,c], C).
C = [a, b] ;
C = [a, c] ;
C = [b, a] ;
C = [b, c] ;
C = [c, a] ;
C = [c, b] ;
false.
And with your example:
?- k_comb(3, [a,b,c,d,e,f], C).
C = [a, b, c] ;
C = [a, b, d] ;
C = [a, b, e] ;
C = [a, b, f] ;
C = [a, c, b] ;
C = [a, c, d] ;
C = [a, c, e] ;
C = [a, c, f] ;
C = [a, d, b] ;
C = [a, d, c] ;
C = [a, d, e] ;
C = [a, d, f] ;
C = [a, e, b] ;
C = [a, e, c] . % and so on
Note that this does not check that the elements of the list in the second argument are indeed unique; it just takes elements from distinct positions.
This solution still has problems with termination but I don't know if this is relevant for you.

Prolog: lexicographic comparison and split a list

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.

Split list on given element

I have a list C and I want to split the list using the element c in the list.
The expected results are as example:
?- split([a,c,a,a,c,a,a,a],X).
X = [[a],[a,a],[a,a,a]].
Can anybody help? Thanks in advance.
I can remove the c in the list now and here is my codes.
split([],[]).
split([H|T],[H|S]) :- H=a,split(T,S).
split([H|T],S) :- H=c,split(T,S).
Your "remove c" predicate would look better like this:
remove_c([c|T], S) :-
remove_c(T, S).
remove_c([a|T], [a|S]) :-
remove_c(T, S).
This still only works for lists that have only c and a in them.
If you want to "split", this means you at least need another argument, to collect the a's between the c's. For example:
split_on_c(List, Split) :-
split_on_c_1(List, Split, []).
split_on_c_1([], [Acc], Acc).
split_on_c_1([c|Rest], [Acc|Split], Acc) :-
split_on_c_1(Rest, Split, []).
split_on_c_1([a|Rest], Split, Acc) :-
split_on_c_1(Rest, Split, [a|Acc]).
Again, this expects lists of a and c only. It could also be done in different ways, but this is a start.
While learning a language you need to get accomplished to common abstractions already established (in simpler terms, use libraries). What about
split(In, Sep, [Left|Rest]) :-
append(Left, [Sep|Right], In), !, split(Right, Sep, Rest).
split(In, _Sep, [In]).
to be used like
?- split([a,c,a,a,c,a,a,a],c,R).
R = [[a], [a, a], [a, a, a]].
Use the meta-predicate splitlistIf/3 together with reified term equality
(=)/3, like this:
Here is the query the OP gave in the question:
?- splitlistIf(=(c),[a,c,a,a,c,a,a,a],Xs).
Xs = [[a],[a,a],[a,a,a]].
Note that above code is monotone, so the following query gives reasonable results:
?- splitlistIf(=(X),[Y,X,Y,Y,X,Y,Y,Y],Xs), Y = a, X = c.
X = c,
Y = a,
Xs = [[a],[a, a],[a, a, a]].

Prolog , Append with no repititions

Hey I'm trying to append two list with no "double" members
for example
A = [a, b, c]
B = [x, c, q]
then ->
append2(A,B,P)
P= [a,b,c,x,q]
I write this code, but it doesn't work...
not_member(_, []).
not_member(X, [Y|Ys]) :- X \= Y, not_member(X, Ys).
append2(A, [], A).
append2([], A, A).
append2([h1|ls], B, [h1|P]) :- not_member(h1, B), !, append2(ls, B, P).
append2([h1|ls], B, P) :- member(h1, P), append2(ls, B, P).
Thanks for helping :)
Assuming there are no variables in your input lists, but allowing duplicates in each list you may write:
append2(A,B,C):-
findall(Item, append2_item(A,B,Item), C).
append2_item(A,_,ItemA):-
append(HeadA, [ItemA|_], A),
\+ member(ItemA, HeadA).
append2_item(A,B,ItemB):-
append(HeadB, [ItemB|_], B),
\+ member(ItemB, HeadB),
\+ member(ItemB, A).
First clause of append2_item/3 selects (ordered) distinct items from the first list. Second clause of append2_item/3 selects (ordered) distinct items from the second list which are not present in the first list.
append2/3 just collects those elements.
Test case:
?- append2([a,b,c,a],[x,c,q,x],C).
C = [a, b, c, x, q].
Check out the pure code in my answer
to the related question "intersection and union of 2 lists"!
Telling from your requirements, predicate list_list_union/3 is just what you are looking for:
?- list_list_union([a,b,c],[x,c,q],Ls).
Ls = [a,b,c,x,q]. % succeeds deterministically
list_list_union/3 is monotone, so we get sound answers
even when using non-ground terms:
?- As = [_,_,_], Bs = [_,_,_], list_list_union(As,Bs,Ls), As = [a,b,c], Bs = [x,c,q].
As = [a,b,c], Bs = [x,c,q], Ls = [a,b,c,x,q] ; % logically sound result
false.

Finding all unifications in prolog

I wrote my first simple code in PROLOG:
is_beginning([], _).
is_beginning([FirstLetterB|RestWordB], [FirstLetterW|RestWordW]) :-
FirstLetterB == FirstLetterW,
is_beginning(RestWordB, RestWordW).
It is designed to find out if first argument of is_beginning is equal to the second one beginning.
Well, IMHO it can answer questions quite well, but now i wonder if there is any possibility of getting all possible answers for defined second argument.
eg. for
is_beginning(Answers, [a,b,c]);
i wish to get
[], [a], [a,b], [a,b,c]
as Answers unification, but I am getting only [] (simplest answer).
Is there any possibility of getting what I want? Maybe there is something wrong in my definition?
I already tried to use findall and forall, but it doesn't work to well for me :(
Thanks for all answers.
you are using (==)/2 when non needed (note the comment at end of documentation page). Indeed, if you change it to 'simple' unification (=)/2 your program works as you expect:
is_beginning([], _).
is_beginning([FirstLetterB|RestWordB], [FirstLetterW|RestWordW]) :-
FirstLetterB = FirstLetterW,
is_beginning(RestWordB, RestWordW).
test:
?- is_beginning(Answers, [a,b,c]).
Answers = [] ;
Answers = [a] ;
Answers = [a, b] ;
Answers = [a, b, c] ;
false.
The interpreter won't immediately return all solutions. When it returns [], press ";" to tell it to continue searching:
?- is_beginning(X, [a,b,c]).
X = [] ;
X = [a] ;
X = [a, b] ;
X = [a, b, c] ;
false.
If you need all these solutions in a Prolog list, rather than just printed out in the console, findall/3 is indeed what you're looking for:
?- findall(X, is_beginning(X, [a,b,c]), L).
L = [[], [a], [a, b], [a, b, c]].

Resources