Prolog, grammar parser - prolog

I am a very green when it comes to prolog, but essentially what I am trying to do is implement recursion to parse a grammar rule. What I have seems to be correct logically but obviously not because I am not getting the expected outcome.
Here is the rule I want to parse:
S -> X Y Z
X -> a X | a
Y -> b Y | b
Z -> c Y | c
Here is the prolog code:
match(X, [X|T], T).
xs(X0, X):- match(a, X0, X).
xs(X0, X):- xs(X0, X).
ys(X0, X):- match(b, X0, X).
ys(X0, X):- ys(X0, X).
zs(X0, X):- match(c, X0, X).
zs(X0, X):- zs(X0, X).
s(X0, X):- xs(X0, X1), ys(X1, X2), zs(X2, X).
Any help in understanding what I am doing wrong would be greatly appreciated.
Cheers.

maybe the grammar translation must be completed, like in
xs(X0, X):- match(a, X0, X).
xs(X0, X):- match(a, X0, X1), xs(X1, X).
...
I would suggest to take a look at the translation that a DCG has to offer:
s --> x,y,z.
x --> [a], x | [a].
y --> [b], y | [b].
z --> [c], y | [c].
consulted and listed results in
z(A, C) :-
( A=[c|B],
y(B, C)
; A=[c|C]
).
y(A, C) :-
( A=[b|B],
y(B, C)
; A=[b|C]
).
x(A, C) :-
( A=[a|B],
x(B, C)
; A=[a|C]
).
s(A, D) :-
x(A, B),
y(B, C),
z(C, D).

In each XS YS ZS method when calling recursively need to call match again.

Related

Avoiding the same answer multiple times in prolog

So I have this undirected graph to traverse, and I should find all the verticies those are connected to a given vertex.
edge(a, b).
edge(b, c).
edge(c, d).
edge(d, e).
edge(e, f).
edge(f, d).
edge(d, g).
edge(g, f).
edge(g, h).
edge(h, i).
edge(i, j).
edge(j, d).
edge(d, k).
edge(l, m).
edge(m, n).
undirectedEdge(X, Y) :- edge(X, Y).
undirectedEdge(X, Y) :- edge(Y, X).
connected(X, Y) :- undirectedEdge(X, Y).
connected(X, Y) :- connected(X, Z), connected(Z, Y), X \= Y.
And once I type connected(a, X). it goes into an infinite loop.
I understand why I have it, but I have no idea how to avoid it, maybe I can find some help here?
Using closure0/3 and setof/3 we get:
connected(A,B) :-
setof(t, closure0(undirectedEdge, A, B), _).
And once I type connected(a, X). it goes into an infinite loop.
The reason this happens is because it is checking a path of the form a → b → a → b → a → b → …. So it keeps "hopping" between two nodes.
You can maintain a list of nodes that the algorithm already visisted, to prevent that like:
connected(X, Y) :-
connected(X, Y, [X]).
connected(X, X, _).
connected(X, Z, L) :-
undirectedEdge(X, Y),
\+ member(Y, L),
connected(Y, Z, [Y|L]).
You can make use of the distinct/1 predicate [swi-doc] to generate distinct answers:
?- distinct(connected(a, X)).
X = a ;
X = b ;
X = c ;
X = d ;
X = e ;
X = f ;
X = g ;
X = h ;
X = i ;
X = j ;
X = k ;
false.

How do I change position of two elements in a list(PROLOG)

predicate change_pos(E1, E2,Lin,Lout).
The Lin has any number of elements, and I need to change all occurences of E1 to E2, and vice-versa. And return in Lout.
I was thinking to do something like this:
change(X, Y, [], []).
change(X, Y, [X|L], [Y,L1]):- change(X,Y,L,L1).
change(X, Y, [Z|L], [Z,L1]:- X \== Z, change(X,Y,L,L1).
But this way is not swiping two number of the list
I'm supposing, since this is homework, it's an exercise to learn list processing and recursion. But in Prolog, a common tool for processing each term in turn in a list is maplist:
% Rule for changing one element
change_element(X, Y, X, Y).
change_element(X, Y, Y, X).
change_element(X, Y, Z, Z) :- dif(X, Z), dif(Y, Z).
% Rule for changing a list
change(X, Y, L1, L2) :-
maplist(change_element(X, Y), L1, L2).
Which yields:
?- change(a, b, [a,b,c,b,a], L).
L = [b, a, c, a, b] ? ;
no
?-
For a determinate solution, you can use if_/3:
change1(X, Y, A, B) :-
if_(=(Y, A), B = X, A = B).
change2(X, Y, A, B) :-
if_(=(X, A), B = Y, change1(X, Y, A, B)).
change(X, Y, L1, L2) :- maplist(change2(X, Y), L1, L2).
Which yields:
?- change(a, b, [a,b,c,b,a], L).
L = [b, a, c, a, b].
?-
You're almost there. Your base case (the empty lists) and your second rule (swap X for Y) are basically fine (apart from the details pointed out in the comments). However, you are missing a rule for vice-versa (swap Y for X). And in your last rule you likely want to make sure that Z differs not only from X but also from Y, otherwise Z would be subject to rule two or three.
change(X, Y, [], []).
change(X, Y, [X|L], [Y|L1]) :-
change(X,Y,L,L1).
change(X, Y, [Y|L], [X|L1]) :- % <- vice versa case
change(X,Y,L,L1).
change(X, Y, [Z|L], [Z|L1]) :-
dif(X,Z), % <- neither X=Z
dif(Y,Z), % <- nor vice versa
change(X,Y,L,L1).
Here are some example queries. What does [1,2,3,4] look like after swapping 1 with 2 and vice versa?
?- change(1,2,[1,2,3,4],L).
L = [2,1,3,4] ? ;
no
What did [2,1,3,4] look like before swapping 1 with 2 and vice versa?
?- change(1,2,L,[2,1,3,4]).
L = [1,2,3,4] ? ;
no
Which elements have been swapped in [1,2,3,4] if the resulting list is [2,1,3,4] ?
?- change(X,Y,[1,2,3,4],[2,1,3,4]).
X = 1,
Y = 2 ? ;
X = 2,
Y = 1 ? ;
no

Select the smallest value from all the repeated elements of a list

An example will explain better what I'm trying to do.
For example, I have this prolog list:
L=[(d,15),(e,16),(g,23),(e,14),(h,23),(d,19)]
And I want to generate this list:
L'=[(d,15),(g,23),(e,14),(h,23)]
This is, from all occurrences of element (X,_), leave the one with the smallest Y.
Not really elegant but... what about the following code?
getFirst((X, _), X).
isMinor(_, []).
isMinor((X1, Y1), [(X2, _) | T]) :-
X1 \= X2,
isMinor((X1, Y1), T).
isMinor((X, Y1), [(X, Y2) | T]) :-
Y1 =< Y2,
isMinor((X, Y1), T).
purgeList(_, [], []).
purgeList(X1, [(X2, Y2) | Tin], [(X2, Y2) | Tout]) :-
X1 \= X2,
purgeList(X1, Tin, Tout).
purgeList(X, [(X, _) | Tin], Tout) :-
purgeList(X, Tin, Tout).
filterList([], []).
filterList([H1 | Tin1], [H1 | Tout]) :-
isMinor(H1, Tin1),
getFirst(H1, X),
purgeList(X, Tin1, Tin2),
filterList(Tin2, Tout).
filterList([H1 | Tin], Tout) :-
\+ isMinor(H1, Tin),
filterList(Tin, Tout).
From
filterList([(d,15),(e,16),(g,23),(e,14),(h,23),(d,19)], L)
I obtain (L is unified with)
[(d,15),(g,23),(e,14),(h,23)]
You could also write:
select_elements(L,Lout):-
sort(L,L1),
reverse(L1,L2),
remove(L2,L3),
output_list(L,L3,Lout).
remove([],[]).
remove([H],[H]).
remove([(X,Y1),(X,Y2)|T],[(X,Y1)|T1]):-remove([(X,Y2)|T],T1).
remove([(X1,Y1),(X2,Y2)|T],[(X1,Y1)|T1]):-
dif(X1,X2),\+member((X2,_),T),
remove([(X2,Y2)|T],T1).
remove([(X1,Y1),(X2,_)|T],[(X1,Y1)|T1]):-
dif(X1,X2),member((X2,_),T),
remove(T,T1).
output_list([],_,[]).
output_list([H|T],L,[H|T1]):-member(H,L),output_list(T,L,T1).
output_list([H|T],L,T1):- \+member(H,L),output_list(T,L,T1).
Example:
?- select_elements([(d,15),(e,16),(g,23),(e,14),(h,23),(d,19)],L).
L = [ (d, 15), (g, 23), (e, 14), (h, 23)] ;
false.
You can try
test((V, N), Y, Z) :-
( member((V,N1), Y)
-> ( N < N1
-> select((V,N1), Y, (V,N), Z)
; Z = Y)
; append(Y, [(V,N)], Z)).
my_select(In, Out) :-
foldl(test, In, [], Out).
For example
?- my_select([(d,15),(e,16),(g,23),(e,14),(h,23),(d,19)], Out).
Out = [(d,15),(e,14),(g,23),(h,23)] ;
false.

On mixing Prolog coroutining (freeze/2, when/2) and DCG

In my previous answer to the recent question "Prolog binary search tree test - unwanted parents' parent node comparison", I proposed mixing lazy_chain/2 which uses prolog-coroutining ...
:- use_module(library(clpfd)).
lazy_chain(Zs, R_2) :-
( var(R_2) -> instantiation_error(R_2)
; clpfd:chain_relation(R_2) -> freeze(Zs, lazy_chain_aux(Zs,R_2))
; otherwise -> domain_error(chain_relation, R_2)
).
lazy_chain_aux([], _).
lazy_chain_aux([Z0|Zs], R_2) :-
freeze(Zs, lazy_chain_aux_(Zs,R_2,Z0)).
lazy_chain_aux_([], _, _).
lazy_chain_aux_([Z1|Zs], R_2, Z0) :-
call(R_2, Z0, Z1),
freeze(Zs, lazy_chain_aux_(Zs,R_2,Z1)).
... together with dcg in_order//1 ...
in_order(nil) --> [].
in_order(node(X,L,R)) --> in_order(L), [X], in_order(R).
... like so:
?- lazy_chain(Zs, #<),
phrase(in_order(node(1,nil,nil)), Zs).
Zs = [1,23].
Is there a easy way to "push" lazy_chain into phrase/3 so that its scope is limited to the part of the sequence described by in_order//1?
Right now, I get ...
?- lazy_chain(Zs, #<),
phrase(in_order(node(1,nil,nil)), Zs0,Zs).
Zs0 = [1|Zs], freeze(Zs, lazy_chain_aux(Zs,#<)).
... which (of course) can fail upon further instantiation of Zs:
?- lazy_chain(Zs, #<),
phrase(in_order(node(1,nil,nil)), Zs0,Zs),
Zs = [3,2,1].
false.
How can I work around that and constrain lazy_chain to the part of the list-difference?
In the meantime I came up with the following hack:
lazy_chain_upto(R_2, P_2, Xs0, Xs) :-
( var(R_2) -> instantiation_error(R_2)
; clpfd:chain_relation(R_2) -> when((nonvar(Xs0) ; ?=(Xs0,Xs)),
lazy_chain_upto_aux(Xs0,Xs,R_2)),
phrase(P_2, Xs0, Xs)
; otherwise -> domain_error(chain_relation, R_2)
).
lazy_chain_upto_aux(Xs0, Xs, _) :-
Xs0 == Xs,
!.
lazy_chain_upto_aux([], _, _).
lazy_chain_upto_aux([X|Xs0], Xs, R_2) :-
when((nonvar(Xs0) ; ?=(Xs0,Xs)), lazy_chain_upto_prev_aux(Xs0,Xs,R_2,X)).
lazy_chain_upto_prev_aux(Xs0, Xs, _, _) :-
Xs0 == Xs,
!.
lazy_chain_upto_prev_aux([], _, _, _).
lazy_chain_upto_prev_aux([B|Xs0], Xs, R_2, A) :-
call(R_2, A, B),
when((nonvar(Xs0) ; ?=(Xs0,Xs)), lazy_chain_upto_prev_aux(Xs0,Xs,R_2,B)).
Based on this we could define in_orderX//1 like this:
in_orderX(T) --> lazy_chain_upto(#<, in_order(T)).
The sample query shown in the question ...
?- phrase(in_orderX(node(1,nil,nil)), Zs0,Zs), Zs = [3,2,1].
Zs0 = [1,3,2,1], Zs = [3,2,1].
... now checks out alright, but still I wonder: is it worth it?
I don't see any problem mixing corouting and DCG. DCG is only a translation from the DCG rules H --> B, to some ordinary Prolog rules H' :- B'. Any constraint posting can be wrapped into {}/1.
Here is an example from Quines:
% eval(+Term, +List, -Term, +Integer)
eval([quote,X], _, X) --> [].
eval([cons,X,Y], E, [A|B]) -->
step,
eval(X, E, A),
eval(Y, E, B).
eval([lambda,X,B], E, [closure,X,B,E]) --> [].
eval([X,Y], E, R) -->
step,
{neq(X, quote), sto(B)},
eval(X, E, [closure,Z,B,F]),
{sto(A)},
eval(Y, E, A),
eval(B, [Z-A|F], R).
eval(S, E, R) -->
{freeze(S, is_symbol(S)), freeze(E, lookup(S, E, R))}.
You could do the same for lazy_chain_upto//2. As a start you
could go on an define the first clause of lazy_chain_upto//2
as follows:
lazy_chain_upto(R_2, P_2) -->
( {var(R_2)} -> {instantiation_error(R_2)}
; {clpfd:chain_relation(R_2)} -> /* ?? */
; {otherwise} -> {domain_error(chain_relation, R_2)}
)
In the /* ?? */ part you could profit from a DCG-ifyed lazy_chain_upto_aux//1 predicate as well. Of course I am assuming that the DCG translation understands (->) and (;)/2.
Bye

Prolog append/3 realization with more determinism?

It is folk knowledge that append(X,[Y],Z) finds the last element
Y of the list Z and the remaining list X.
But there is some advantage of having a customized predicate last/3,
namely it can react without leaving a choice point:
?- last([1,2,3],X,Y).
X = 3,
Y = [1,2]
?- append(Y,[X],[1,2,3]).
Y = [1,2],
X = 3 ;
No
Is there a way to realize a different implementation of
append/3 which would also not leave a choice point in the
above example?
P.S.: I am comparing:
/**
* append(L1, L2, L3):
* The predicate succeeds whenever L3 unifies with the concatenation of L1 and L2.
*/
% append(+List, +List, -List)
:- public append/3.
append([], X, X).
append([X|Y], Z, [X|T]) :- append(Y, Z, T).
And (à la Gertjan van Noord):
/**
* last(L, E, R):
* The predicate succeeds with E being the last element of the list L
* and R being the remainder of the list.
*/
% last(+List, -Elem, -List)
:- public last/3.
last([X|Y], Z, T) :- last2(Y, X, Z, T).
% last2(+List, +Elem, -Elem, -List)
:- private last2/4.
last2([], X, X, []).
last2([X|Y], U, Z, [U|T]) :- last2(Y, X, Z, T).
One way to do it is to use foldl/4 with the appropriate help predicate:
swap(A, B, B, A).
list_front_last([X|Xs], F, L) :-
is_list(Xs),
foldl(swap, Xs, F, X, L).
This should be it:
?- list_front_last([a,b,c,d], F, L).
F = [a, b, c],
L = d.
?- list_front_last([], F, L).
false.
?- list_front_last([c], F, L).
F = [],
L = c.
?- Ys = [y|Ys], list_front_last(Ys, F, L).
false.
Try to see if you can leave out the is_list/1 from the definition.
As I posted:
append2(Start, End, Both) :-
% Preventing unwanted choicepoint with append(X, [1], [1]).
is_list(Both),
is_list(End),
!,
append(Start, End, Both),
!.
append2(Start, End, Both) :-
append(Start, End, Both),
% Preventing unwanted choicepoint with append(X, Y, [1]).
(End == [] -> ! ; true).
Result in swi-prolog:
?- append2(Y, [X], [1,2,3]).
Y = [1, 2],
X = 3.

Resources