Prolog string manipulation - prolog

I have a string like 'pen,pencil,eraser'. How can I make this predicate.
things(pen,pencil,eraser).
Do you have any idea? ( I use prolog)

Here's a small example of specialized Prolog code for your problem which should work on most implementations (not only SWI-Prolog, but GNU Prolog, SICStus, etc.):
make_term(Functor, StringArgs, Term) :-
split_atom(StringArgs, ',', Args),
Term =.. [Functor|Args].
split_atom(A, E, L) :-
atom_chars(A, C),
split_atom2(C, E, L).
split_atom2([], _, []).
split_atom2(C, E, [A|L]) :-
append(C0, [E|C1], C), !,
atom_chars(A, C0),
split_atom2(C1, E, L).
split_atom2(C, _, [A]) :-
atom_chars(A, C).
Testing it out:
?- make_term(things, 'pen,pencil,eraser', T).
T = things(pen, pencil, eraser).

if you use swi-prolog, you can create this first: 'things(pen,pencil,eraser)' and then use term_to_atom/2
so something like:
get_term(Term):-
atom_concat('things(','pen,pencil,eraser',Temp),
atom_concat(Temp,')',A),
term_to_atom(Term, A).

Related

How to link constant with variable by assert?

I want to add in the DB a constant and a linked variable:
?- assertz(my(x, A))
So that in the future I can define A and get the only one entry. Sth like that:
?- assertz(my(x, A)), ..., A = 2.
?- my(A, B).
A = x,
B = 2.
Can this be done?
As I noted in the comments your idea of a link like a pointer is not the way to approach solving your problem.
A common solution is to walk the tree and construct a new tree as you walk the tree by replacing the leaf of the tree with a new leaf that contains the value from the input tree along with the associated value, what you are thinking should be linked.
Since you are somewhat new to Prolog I will do this with two examples. The first will just walk a tree and only return true when successfully walked. It can be used to understand how to walk a tree and run with gtrace to single step the code to understand it.
The second example will expand on the tree walk and add the type (link as you think) to the leaf item. The the old leaf for something simple like an atom a, will become a new leaf in the tree like (a,atom).
Also this was quickly written as a demonstration only. I am sure it will have problems if pressed into doing anything more than the single example.
:- module(example,
[
example/1
]).
example(walk) :-
Term = term_size(a(1,"Hello",'Atom',1+2,[a,$,T])),
walk(Term).
example(infer_type) :-
Term = term_size(a(1,"Hello",'Atom',1+2,[a,$,T])),
infer_type(Term,Is),
write(Is).
walk([]) :- !.
walk([T]) :- var(T), !.
walk(L) :- is_list(L), !, L = [H|T], walk(H), walk(T).
walk(T) :- compound(T), !, T =.. [_|Args], !, walk(Args).
walk(T) :- integer(T), !.
walk(T) :- var(T), !.
walk(T) :- atomic(T), !.
walk(T) :- T =.. [Arg|Args], !, walk(Arg), walk(Args).
infer_type([],[]) :- !.
infer_type([T],[(T,var)]) :- var(T), !.
infer_type(L,S) :- is_list(L), !, L = [H|T], infer_type(H,I), infer_type(T,Is), S = [I|Is].
infer_type(T,S) :- compound(T), !, T =.. [F|Args], !, infer_type(Args,Is), S =.. [F|Is].
infer_type(T,(T,integer)) :- integer(T), !.
infer_type(T,(T,var)) :- var(T), !.
infer_type(T,(T,atom)) :- atomic(T), !.
infer_type(T,S) :- T =.. [Arg|Args], !, infer_type(Arg,I), infer_type(Args,Is), S =.. [I|Is].
Example run
Note: I know there are warnings; it is a demo not production code.
Welcome to SWI-Prolog (threaded, 64 bits, version 8.5.3)
?- working_directory(_,'C:/Users/Groot').
true.
?- [example].
Warning: c:/users/Groot/example.pl:20:
Warning: Singleton variables: [T]
Warning: c:/users/Groot/example.pl:24:
Warning: Singleton variables: [T]
true.
?- example(walk).
true.
?- example(infer_type).
term_size(a((1,integer),(Hello,atom),(Atom,atom),(1,integer)+(2,integer),[(a,atom),(($),atom),(_25642,var)]))
true.
As an exercise I did not identify the string as a string, the change should be easy.

Use findall with arg

I'm learning Prolog and I try to rewrite the univ predicate:
?- foo(hello, X) =.. List.
List = [foo, hello, X]
?- Term =.. [baz, foo(1)].
Term = baz(foo(1))
I already wrote a first version that works well:
get_args(_, Arity, Arity, []).
get_args(T, Arity, N, [Arg|Args]) :-
I is N + 1,
arg(I, T, Arg),
get_args(T, Arity, I, Args).
univ(T, [Functor|Args]) :-
length(Args, Arity),
functor(T, Functor, Arity),
get_args(T, Arity, 0, Args),
!
I wanted to try another way to implement it. So, I rewrite this one by using findall and arg:
univ(T, [Functor|Args]) :-
length(Args, Arity),
functor(T, Functor, Arity),
findall(Arg, arg(_, T, Arg), Args),
!.
This one doesn't work well. Here is an example:
?- univ(a(C, D, E), L).
L = [a, _G1312, _G1315, _G1318].
?- univ(T, [a, C, D, E]).
T = a(_G1325, _G1326, _G1327).
Thus, I have a simple question: is it possible to use arg with findall in order to retrieve the name of each arguments?
As noted by #mat, findall/3 copies variables. You can use bagof/3 instead:
univ(T, [Functor|Args]) :-
length(Args, Arity),
functor(T, Functor, Arity),
bagof(Arg, I^arg(I, T, Arg), Args),
!.
?- univ(a(C, D, E), L).
L = [a, C, D, E].
This different behaviour wrt findall/3 and setof/3 can also be useful when you need to handle attributed variables.

Transposing a Matrix in prolog

I have written the following code below to transpose a Matrix in prolog
listFirst([],[]).
listFirst([H1|T1],[H2|Z]):-
H1 = [H2|_],
listFirst(T1,Z).
listFollowers([],[]).
listFollowers([H1|T1],[T2|Z]):-
H1 = [H2|T2],
listFollowers(T1,Z).
decompose(A,L1,L2):-
listFollowers(A,L2),listFirst(A,L1).
transpose([],[]).
transpose([H|T],[L1|R]):-
decompose([H|T],L1,L2),
transpose(L2,R).
Test Case
transpose([[1,2],[3,4],[5,6]], R).
R = [[1,3,5],[2,4,6]] ;
I am having problems with the transpose predicate no sure how to implement this. Other predicates seem to work okay.
Taken from library(clpfd) in SWI-Prolog (see the source code for more information):
transpose([], []).
transpose([L|Ls], Ts) :- foldl(transpose_, L, Ts, [L|Ls], _).
transpose_(_, Fs, Lists0, Lists) :-
maplist(list_first_rest, Lists0, Fs, Lists).
list_first_rest([L|Ls], L, Ls).
Example query:
?- transpose([[a,b,c],[d,e,f]], Ts).
Ts = [[a, d], [b, e], [c, f]].
my old code - rather efficient tough
transpose_col_row([], []).
transpose_col_row([U], B) :- gen(U, B).
transpose_col_row([H|T], R) :- transpose_col_row(T, TC), splash(H, TC, R).
gen([H|T], [[H]|RT]) :- gen(T,RT).
gen([], []).
splash([], [], []).
splash([H|T], [R|K], [[H|R]|U]) :-
splash(T,K,U).
This might help.
If you change the base case in order to have the lists of lists to a complete list it will work. Even though it probably won`t be the most efficient method, since it will only be able to get up to 4 lists. This means a matrix of four rows.
transpose([[X],[Y],[Z],[B]],[[X,Y,Z,B]]).
transpose([H|T],[L1|R]):-
decompose([H|T],L1,L2),
transpose(L2,R).

Change goal execution order in Prolog Interpreter

I'm attempting to write a Prolog meta-interpreter to choose the order of goal execution, for example executing first all goals with the minimum number of parameters.
I started from the vanilla meta-interpreter:
solve2(true).
solve2(A) :- builtin(A), !, A.
solve2((A,B)) :- solve2(A), solve2(B).
solve2(A) :- clause(A,B), solve2(B).
Then i went to something like
solve2(true).
solve2(A) :- builtin(A), !, A.
solve2((A,B)) :- count(A,Args), count(B,Args2), Args<Args2, solve2(A), solve2(B).
solve2((A,B)) :- count(A,Args), count(B,Args2), Args>Args2, solve2(B), solve2(A).
solve2(A) :- clause(A,B), solve2(B).
But if the 4th line is executed then the whole block B is executed before A which is wrong.
Ex. A=a(x,y), B=(b(x,y,z), c(x)) I'd like to execute c, then a, then b. - while in this method i'd get c, b and then a.
I'm thinking about transforming the goals in a list but i'm not too sure.
Any ideas?
Here is an (untested) vanilla meta interpreter, with conjunction order changed. I would be glad if you could try with your data.
solve2(true).
solve2(A) :- builtin(A), !, A.
solve2((A,B)) :- ordering(A,B, C,D), ! /* needed */, solve2(C), solve2(D).
solve2(A) :- clause(A,B), solve2(B).
ordering(A,B, C,D) :-
minargs(A, NA),
minargs(B, NB),
( NA =< NB -> C/D=A/B ; C/D=B/A ).
minargs((A,B), N) :-
minargs(A, NA),
minargs(B, NB),
!, ( NA =< NB -> N=NA ; N=NB ).
minargs(T, N) :-
functor(T, _, N).
edit I tested with this setting:
builtin(writeln(_)).
a(1):-writeln(1).
b(1,2):-writeln(2).
c(1,2,3):-writeln(3).
test :-
solve2((c(A,B,_),a(A),b(A,B))).
and got the expected output:
?- test.
1
2
3
true .
edit I had to resort to a list representation, but then it make sense to preprocess the clauses and get the right order before, then stick to plain vanilla interpreter:
test :-
sortjoin((b(A,B),a(A),c(A,B,_)), X),
solve2(X).
sortjoin(J, R) :-
findall(C-P, (pred(J, P), functor(P,_,C)), L),
sort(L, T),
pairs_values(T, V),
join(V, R).
join([C], C).
join([H|T], (H,R)) :- join(T, R).
pred((A, _), C) :-
pred(A, C).
pred((_, B), C) :-
!, pred(B, C).
pred(C, C).
where solve2((A,B)) :- ... it's the original solve2(A),solve2(B)

Prolog: converting atom to new atom

I have a problem with predicate which works in that way that it takes list of atoms:
nopolfont([to,jest,tekśćik,'!'],L).
and in result
L = [to,jest,tekscik,'!'].
I have problem with make_swap and swap predicates. So far I have:
k(ś,s).
k(ą,a).
% etc.
swap(X,W) :- name(X,P), k(P,Y), !, name(Y,W).
swap(X,X).
make_swap(A,W)
:- atom(A),!,
name(A,L),
swap(L,NL),
name(W,NL).
nopolfont([],[]).
nopolfont([H|T],[NH|S]) :- make_swap(H,NH), nopolfont(T,S).
Is there any elegant way to do this?
This is also quite elegant:
polish_char_replacer(X, Y) :-
k(X, Y),
!.
polish_char_replacer(X, X).
nopolfont(Atoms1, Atoms2) :-
maplist(replace(polish_char_replacer), Atoms1, Atoms2).
replace(Goal, Atom1, Atom2) :-
atom_chars(Atom1, Chars1),
maplist(Goal, Chars1, Chars2),
atom_chars(Atom2, Chars2).
Probably as elegant as it can get:
k(ś,s).
k(ą,a).
swap(X,W) :- name(P,[X]), k(P,Y), !, name(Y,[W]).
swap(X,X).
list_swap([], []).
list_swap([H|T], [W|S]) :-
swap(H, W),
list_swap(T, S).
atom_swap(A,W) :-
atom(A), !,
name(A, L),
list_swap(L,S),
name(W, S).
nopolfont([],[]).
nopolfont([H|T],[NH|S]) :-
atom_swap(H,NH),
nopolfont(T,S).
Also, obviously define this, to get the expected result, but I assume this is in the % etc
k(ć, c).

Resources