Related
So check the exercize 3.5 description here:
%% Exercise 3.5 %%
% Binary trees are trees where all internal nodes have exactly two children.
% The smallest binary trees consist of only one leaf node. We will represent leaf nodes as
% leaf(Label) . For instance, leaf(3) and leaf(7) are leaf nodes, and therefore small binary
% trees. Given two binary trees B1 and B2 we can combine them into one binary tree using the
% functor tree/2 as follows: tree(B1,B2) . So, from the leaves leaf(1) and leaf(2) we can build
% the binary tree tree(leaf(1),leaf(2)) . And from the binary trees tree(leaf(1),leaf(2)) and
% leaf(4) we can build the binary tree tree(tree(leaf(1), leaf(2)),leaf(4)).
% Now, define a predicate swap/2 , which produces the mirror image of the binary tree that is its first argument. For example:
% ?- swap(tree(tree(leaf(1), leaf(2)), leaf(4)),T).
% T = tree(leaf(4), tree(leaf(2), leaf(1))).
% yes
And this is my implementation:
swap(tree(leaf(X), leaf(Y)), tree(leaf(Y), leaf(X))).
swap(tree(B1, leaf(Y)), tree(leaf(Y), SwapB1)) :-
dif(B1, leaf(_)),
swap(B1, SwapB1).
swap(tree(leaf(X), B2), tree(SwapB2, leaf(X))) :-
dif(B2, leaf(_)),
swap(B2, SwapB2).
swap(tree(B1, B2), tree(B2,B1)) :-
dif(B1, leaf(_)),
dif(B2, leaf(_)).
When I execute the following query swap(T1,T). I get:
?- swap(T1,T).
T1 = tree(leaf(_A), leaf(_B)),
T = tree(leaf(_B), leaf(_A)) ;
T1 = tree(tree(leaf(_A), leaf(_B)), leaf(_C)),
T = tree(leaf(_C), tree(leaf(_B), leaf(_A))) ;
T1 = tree(tree(tree(leaf(_A), leaf(_B)), leaf(_C)), leaf(_D)),
T = tree(leaf(_D), tree(leaf(_C), tree(leaf(_B), leaf(_A)))) ;
T1 = tree(tree(tree(tree(leaf(_A), leaf(_B)), leaf(_C)), leaf(_D)), leaf(_E)),
T = tree(leaf(_E), tree(leaf(_D), tree(leaf(_C), tree(leaf(_B), leaf(_A))))) .
As you can see Prolog is not considering all of the solutions for each number of leaves N. For example, for N = 4, the case T1 = tree( tree(leaf(_A) , leaf(_B)), tree(leaf(_C), leaf(_D)) ) is not being considered.
Edit: changed the case N=3 to N=4, now i think it's more clear.
I'm trying to make Prolog consider all solutions for each number of leaves N of the tree without relying on CLPFD as suggested before by user #false
Thank you for your attention!
Your problem is called fairness of enumeration. Prolog's backtracking algorithm explores the last recursive call in a goal as deeply as possible, so if you have two recursive calls in a goal, enumeration will always get "stuck" in the second one.
Here's a simpler example, just enumerating trees:
tree(leaf(_)).
tree(tree(Left, Right)) :-
tree(Left),
tree(Right).
Just like in your case, this builds trees that deepen to the right:
?- tree(Tree).
Tree = leaf(_1986) ;
Tree = tree(leaf(_1992), leaf(_1996)) ;
Tree = tree(leaf(_1992), tree(leaf(_2002), leaf(_2006))) ;
Tree = tree(leaf(_1992), tree(leaf(_2002), tree(leaf(_2012), leaf(_2016)))) ;
Tree = tree(leaf(_1992), tree(leaf(_2002), tree(leaf(_2012), tree(leaf(_2022), leaf(_2026))))) .
The fix for this is to introduce some kind of "size" measure, like the number of leaves, and to enumerate guided by the size. This is why using CLPFD arithmetic was suggested. Without arithmetic, one way of doing this is with lists.
Here is a predicate that relates trees and lists of their leaves:
tree_leaves(leaf(X), [X]).
tree_leaves(tree(Left, Right), Leaves) :-
LeftLeaves = [_ | _],
RightLeaves = [_ | _],
append(LeftLeaves, RightLeaves, Leaves),
tree_leaves(Left, LeftLeaves),
tree_leaves(Right, RightLeaves).
For example:
?- Leaves = [a, b, c], tree_leaves(Tree, Leaves).
Leaves = [a, b, c],
Tree = tree(leaf(a), tree(leaf(b), leaf(c))) ;
Leaves = [a, b, c],
Tree = tree(tree(leaf(a), leaf(b)), leaf(c)) ;
false.
As you can see, for a fixed-length list, this did enumerate all (two) possible tree structures.
So now we want to do something similar with a fair enumeration of all fixed-length lists -- this will force a fair enumeration of the corresponding trees. Lists can be enumerated fairly with the length/2 predicate:
?- length(List, N).
List = [],
N = 0 ;
List = [_2242],
N = 1 ;
List = [_2242, _2248],
N = 2 ;
List = [_2242, _2248, _2254],
N = 3 ;
List = [_2242, _2248, _2254, _2260],
N = 4 .
Therefore:
?- length(Leaves, N), tree_leaves(Tree, Leaves).
Leaves = [_2798],
N = 1,
Tree = leaf(_2798) ;
Leaves = [_2798, _2804],
N = 2,
Tree = tree(leaf(_2798), leaf(_2804)) ;
Leaves = [_2798, _2804, _2810],
N = 3,
Tree = tree(leaf(_2798), tree(leaf(_2804), leaf(_2810))) ;
Leaves = [_2798, _2804, _2810],
N = 3,
Tree = tree(tree(leaf(_2798), leaf(_2804)), leaf(_2810)) ;
Leaves = [_2798, _2804, _2810, _2816],
N = 4,
Tree = tree(leaf(_2798), tree(leaf(_2804), tree(leaf(_2810), leaf(_2816)))) ;
Leaves = [_2798, _2804, _2810, _2816],
N = 4,
Tree = tree(leaf(_2798), tree(tree(leaf(_2804), leaf(_2810)), leaf(_2816))) ;
Leaves = [_2798, _2804, _2810, _2816],
N = 4,
Tree = tree(tree(leaf(_2798), leaf(_2804)), tree(leaf(_2810), leaf(_2816))) ;
Leaves = [_2798, _2804, _2810, _2816],
N = 4,
Tree = tree(tree(leaf(_2798), tree(leaf(_2804), leaf(_2810))), leaf(_2816)) ;
Leaves = [_2798, _2804, _2810, _2816],
N = 4,
Tree = tree(tree(tree(leaf(_2798), leaf(_2804)), leaf(_2810)), leaf(_2816)) ;
Leaves = [_2798, _2804, _2810, _2816, _2822],
N = 5,
Tree = tree(leaf(_2798), tree(leaf(_2804), tree(leaf(_2810), tree(leaf(_2816), leaf(_2822))))) .
We can package this up:
fairtree(Tree) :-
length(Leaves, _N),
tree_leaves(Tree, Leaves).
And then test your swap/2 predicate with fair enumeration:
?- fairtree(Tree), swap(Tree, Swapped).
Tree = tree(leaf(_2122), leaf(_2128)),
Swapped = tree(leaf(_2128), leaf(_2122)) ;
Tree = tree(leaf(_2874), leaf(_2878)),
Swapped = tree(leaf(_2878), leaf(_2874)),
dif(_2906, _2874),
dif(_2918, _2878) ;
Tree = tree(leaf(_2122), tree(leaf(_2128), leaf(_2134))),
Swapped = tree(tree(leaf(_2134), leaf(_2128)), leaf(_2122)) ;
Tree = tree(leaf(_2922), tree(leaf(_2932), leaf(_2936))),
Swapped = tree(tree(leaf(_2936), leaf(_2932)), leaf(_2922)),
dif(_2974, _2932),
dif(_2986, _2936) ;
Tree = tree(leaf(_2690), tree(leaf(_2700), leaf(_2704))),
Swapped = tree(tree(leaf(_2700), leaf(_2704)), leaf(_2690)),
dif(_2732, _2690) ;
Tree = tree(tree(leaf(_2122), leaf(_2128)), leaf(_2134)),
Swapped = tree(leaf(_2134), tree(leaf(_2128), leaf(_2122))) ;
Tree = tree(tree(leaf(_2934), leaf(_2938)), leaf(_2942)),
Swapped = tree(leaf(_2942), tree(leaf(_2938), leaf(_2934))),
dif(_2980, _2934),
dif(_2992, _2938) ;
Tree = tree(tree(leaf(_2702), leaf(_2706)), leaf(_2710)),
Swapped = tree(leaf(_2710), tree(leaf(_2702), leaf(_2706))),
dif(_2738, _2710) ;
Tree = tree(leaf(_2122), tree(leaf(_2128), tree(leaf(_2134), leaf(_2140)))),
Swapped = tree(tree(tree(leaf(_2140), leaf(_2134)), leaf(_2128)), leaf(_2122)) ;
Tree = tree(leaf(_2970), tree(leaf(_2980), tree(leaf(_2990), leaf(_2994)))),
Swapped = tree(tree(tree(leaf(_2994), leaf(_2990)), leaf(_2980)), leaf(_2970)),
dif(_3042, _2990),
dif(_3054, _2994) ;
Tree = tree(leaf(_2738), tree(leaf(_2748), tree(leaf(_2758), leaf(_2762)))),
Swapped = tree(tree(tree(leaf(_2758), leaf(_2762)), leaf(_2748)), leaf(_2738)),
dif(_2800, _2748) ;
Tree = tree(leaf(_2724), tree(leaf(_2734), tree(leaf(_2744), leaf(_2748)))),
Swapped = tree(tree(leaf(_2734), tree(leaf(_2744), leaf(_2748))), leaf(_2724)),
dif(_2776, _2724) .
(For whatever it's worth, the canonical definition of swap is much shorter and simpler than yours. Two clauses are enough.)
Bad usage of dif/2
First some remarks on the goal dif(B1, leaf(_)). With this you intend to express that it should only be true if B1 is not a leaf. But what you said is that B1 should be different to a very particular leaf structure whose argument does not occur anywhere else. In other words, there is no term for B1 that makes this goal fail.
(Both Scryer and SWI have here a bug with the anonymous variable. So let's use _A instead.)
?- B1 = leaf(2), dif(B1, leaf(_A)).
B1 = leaf(2), dif:dif(leaf(2),leaf(_A)).
That is certainly not what you intend. What you meant was that this dif should be true for all _A. Or otherwise, that the functor of B1 must be different to leaf/1. There is no common way to express this idiomatically. But in your case, just consider which trees are not leaves! Certainly, they must look like tree(_,_). So you can replace that goal and all others by B1 = tree(_,_).
Mirroring a tree
Then for your definition of swap/2: It fails for swap(leaf(1),T). That might give you a clue. In general it is very often an error to try to specialize a program into too many separate cases. Instead, try to keep it as simple as possible. For that take the definition of a tree as a starting template, and fill in the remainder:
is_tree(leaf(_)).
is_tree(tree(L, R)) :-
is_tree(L),
is_tree(R).
% Version 0, too general w.r.t. the second argument, but otherwise fine
swap_v0(leaf(_), _).
swap_v0(tree(L,R), _) :-
swap_v0(L, _),
swap_v0(R, _).
Counterexample:
?- swap_v0(leaf(_), anything).
true. % unexpected
Evidently, this definition is too general, this anything is pointless. So we need to specialize the program. Let's do this very slowly:
swap_v1(leaf(E), leaf(E)).
swap_v1(tree(L,R), tree(_,_)) :-
swap_v1(L, _),
swap_v1(R, _).
Still too general, I will leave the rest to you.
Enumerating infinite answers/solutions
Prolog is very good at enumerating one infinite set that is described with infinitely many answers:
?- length(L, N).
L = [], N = 0
; L = [_A], N = 1
; L = [_A,_B], N = 2
; L = [_A,_B,_C], N = 3
; L = [_A,_B,_C,_D], N = 4
; L = [_A,_B,_C,_D,_E], N = 5
; ... .
It is only because of the finite space limit here on SO that we cannot have the entire sequence of answers. (Just kidding, it's because we have finite machines, always the cheap ones.) But just tell me a number and I will tell you were this number will appear. That's essentially what a fair enumeration is about.
But now consider that we want to have one further list:
?- length(L, N), length(K, M).
L = [], N = 0, K = [], M = 0
; L = [], N = 0, K = [_A], M = 1
; L = [], N = 0, K = [_A,_B], M = 2
; L = [], N = 0, K = [_A,_B,_C], M = 3
; L = [], N = 0, K = [_A,_B,_C,_D], M = 4
; L = [], N = 0, K = [_A,_B,_C,_D,_E], M = 5
; ... .
So here we have two infinite sets but only one is enumerated in a fair manner. That is the problem with chronological backtracking. We need to reformulate such queries in such a manner that only a single infinite sequence of answers will be produced.
Same problem with enumerating is_tree/2. Except that here it is a bit more confusing if you attempt to follow Prolog's execution step-by-step. Don't try it, yes there are tracers out there, but you will not understand this with the help of them. Instead, try to find some size-like norm such that for each such size, Prolog will enumerate all corresponding trees with finitely many answers. Like the number of leaves. Or, even better the list of all leaves. That is, for each such list, Prolog will enumerate all corresponding trees. Here is such a definition:
tree_leaves(T, Es) :-
Es = [_|Ls],
phrase(tree(T, Ls,[]), Es).
tree(leaf(E), Ls,Ls) --> [E].
tree(tree(L,R), [_|Ls0],Ls) -->
tree(L, Ls0,Ls1),
tree(R, Ls1,Ls).
Now all trees can be enumerated like so:
?- length(Es, N), tree_leaves(T, Es).
Es = [_A], N = 1, T = leaf(_A)
; Es = [_A,_B], N = 2, T = tree(leaf(_A),leaf(_B))
; Es = [_A,_B,_C], N = 3, T = tree(leaf(_A),tree(leaf(_B),leaf(_C)))
; Es = [_A,_B,_C], N = 3, T = tree(tree(leaf(_A),leaf(_B)),leaf(_C))
; Es = [_A,_B,_C,_D], N = 4, T = tree(leaf(_A),tree(leaf(_B),tree(leaf(_C),leaf(_D))))
; Es = [_A,_B,_C,_D], N = 4, T = tree(leaf(_A),tree(tree(leaf(_B),leaf(_C)),leaf(_D)))
; Es = [_A,_B,_C,_D], N = 4, T = tree(tree(leaf(_A),leaf(_B)),tree(leaf(_C),leaf(_D)))
; Es = [_A,_B,_C,_D], N = 4, T = tree(tree(leaf(_A),tree(leaf(_B),leaf(_C))),leaf(_D))
; Es = [_A,_B,_C,_D], N = 4, T = tree(tree(tree(leaf(_A),leaf(_B)),leaf(_C)),leaf(_D))
; Es = [_A,_B,_C,_D,_E], N = 5, T = tree(leaf(_A),tree(leaf(_B),tree(leaf(_C),tree(leaf(_D),leaf(_E)))))
; ... .
Test your code
With tree_leaves/2 you can now also test your definition of swap/2! The following must never succeed
?- any(Es), tree_leaves(T, Es), reverse(Es, EsR),
\+ ( swap(T, TS),
tree_leaves(TS, EsS),
EsS == EsR
).
I am trying to define a Prolog DCG for the set of strings 0^N 1^M 2^N+M of length 2N + 2M for N, M >= 0 using extra arguments. An example of a correct string would be "011222" but not "012".
I have used the following code to create this DCG.
s --> a(N), b(M), c(N), c(M).
a(0) --> [].
a(succ(X)) --> [0], a(X).
b(0) --> [].
b(succ(X)) --> [1], b(X).
c(0) --> [].
c(succ(X)) --> [2], c(X).
When I run the query
s([0,1,1,2,2,2], []).
Prolog returns true as expected.
However when I run
s(X, []).
Prolog returns the following:
X = []
X = [1,2]
X = [1,1,2,2]
X = [1,1,1,2,2,2]
These are not valid strings. I think this may be because N and M are being decremented by the c predicate before prolog runs the a and b predicates. Is this the case? How could this be resolved?
Edit:
I've tried modifying the s production to this:
s --> a(N), b(M), c(NplusM), {NplusM is N + M}.
but that gives an error when running queries.
IMO the answers you are getting are correct!
I renamed your grammar from s to aN_bM_cNM and added two additional arguments, one for N, the other for M. Also, I renamed succ to s:
aN_bM_cNM(N, M) --> n_reps(N, 0), n_reps(M, 1), n_reps(N, 2), n_reps(M, 2).
n_reps( 0 , _) --> [].
n_reps(s(N), E) --> [E], n_reps(N, E).
Now let's run the query that #CapelliC gave. The goal length(Xs, _) ensures fair enumeration of the infinite solution set of aN_bM_cNM//2:
?- length(Xs, _), phrase(aN_bM_cNM(N,M), Xs).
( Xs = [] , N = 0 , M = 0
; Xs = [1,2] , N = 0 , M = s(0)
; Xs = [0,2] , N = s(0) , M = 0
; Xs = [1,1,2,2] , N = 0 , M = s(s(0))
; Xs = [0,1,2,2] , N = s(0) , M = s(0)
; Xs = [0,0,2,2] , N = s(s(0)) , M = 0
; Xs = [1,1,1,2,2,2] , N = 0 , M = s(s(s(0)))
; Xs = [0,1,1,2,2,2] , N = s(0) , M = s(s(0))
; Xs = [0,0,1,2,2,2] , N = s(s(0)) , M = s(0)
; Xs = [0,0,0,2,2,2] , N = s(s(s(0))), M = 0
; Xs = [1,1,1,1,2,2,2,2], N = 0 , M = s(s(s(s(0))))
...
To raise the lower bound of N or M, just state an additional goal of the form X = s(s(_)) (for a minimum value of 2).
In the following query both N and M are to be greater than 0:
?- N = s(_) , M = s(_) , length(Xs, _), phrase(aN_bM_cNM(N,M), Xs).
( N = s(0) , M = s(0) , Xs = [0,1,2,2]
; N = s(0) , M = s(s(0)) , Xs = [0,1,1,2,2,2]
; N = s(s(0)), M = s(0) , Xs = [0,0,1,2,2,2]
; N = s(0) , M = s(s(s(0))), Xs = [0,1,1,1,2,2,2,2]
...
You're misusing succ/2, maybe because you expect Prolog evaluates functions in head patterns. It doesn't. Then, try to replace your rules with
a(0) --> [].
a(Y) --> {succ(X,Y)}, [0], a(X).
etc etc
edit since succ/2 needs at least one argument instantiated to an integer, we could supply N,M to the DCG entry, or, using CLP(FD):
:- use_module(library(clpfd)).
s --> a(N), b(M), c(N), c(M).
a(0) --> [].
a(Y) --> {Y #= X-1}, [0], a(X).
b(0) --> [].
b(Y) --> {Y #= X-1}, [1], b(X).
c(0) --> [].
c(Y) --> {Y #= X-1}, [2], c(X).
but still, list' length must be provided. For example
?- length(L,_),phrase(s,L).
L = [] ;
L = [1, 2] ;
L = [0, 2] ;
L = [1, 1, 2, 2] ;
L = [0, 1, 2, 2] ;
L = [0, 0, 2, 2] ;
...
my game is about picking the max set of elements from a given list that their sum is N
example : L=[1,1,2,2,3,2,4,5,6], N = 6 , Sub List would be equal to [1,1,2,2]
I need a hint using constraint logic programming.
There is a library for Constrained Logic Programming in SWI-Prolog. It's called clpfd.
:-use_module(library(clpfd)).
Let's say that you'll have a variable for the length of the subsequence. Its domain goes from zero (corresponding to the empty subsequence) to the length of the list. In order to get the longest sequence first, values should be tried starting with the highest.
...
length(List, M),
L in 0..M,
labeling([max(L)],[L]),
...
Next, L can be used to build a list of L variables that would correspond to indices of elements from List. As these indices must be in ascending order, chain/2 can be used to create #</2 constraints between any two consecutive indices.
...
length(Indices, L),
Indices ins 1..M,
chain(Indices, #<),
...
Using these indices, a list with elements from List can be constructed. nth1/3 is useful here, but with a minor trick.
...
nth1a(List, N, E):-
nth1(N, List, E).
...
maplist(nth1a(List), Indices, SubSequence),
...
And the sum of that list must be N:
...
sum(SubSequence, #=, N)
...
As only the longest sequence is needed, once/1 can be used to stop after first solution is found.
Some example queries:
?- longest_subsequence([1,1,4,4,6], 9, S).
S = [1, 4, 4].
?- longest_subsequence([1,1,4,4,6], 11, S).
S = [1, 4, 6].
?- longest_subsequence([1,1,4,4,6], 21, S).
false.
As I am not sure if that's a homework or not, I won't post the full code here.
In this answer we use clpfd and a little lambda:
:- use_module([library(clpfd),
library(lambda)]).
Based on meta-predicate maplist/4 and the constraints (ins)/2 and sum/3 we define:
zs_selection_len_sum(Zs, Bs, L, S) :-
same_length(Zs, Bs),
Bs ins 0..1,
maplist(\Z^B^X^(X #= Z*B), Zs, Bs, Xs),
sum(Bs, #=, L),
sum(Xs, #=, S).
Sample queries using labeling/2 with option max/1:
?- zs_selection_len_sum([1,1,4,4,6],Bs,L,8), labeling([max(L)],Bs).
Bs = [1,1,0,0,1], L = 3
; Bs = [0,0,1,1,0], L = 2
; false.
?- zs_selection_len_sum([1,1,3,4,5],Bs,L,7), labeling([max(L)],Bs).
Bs = [1,1,0,0,1], L = 3
; Bs = [0,0,1,1,0], L = 2
; false.
?- zs_selection_len_sum([1,1,2,2,3,2,4,5,6],Bs,L,6), labeling([max(L)],Bs).
Bs = [1,1,0,1,0,1,0,0,0], L = 4
; Bs = [1,1,1,0,0,1,0,0,0], L = 4
; Bs = [1,1,1,1,0,0,0,0,0], L = 4
; Bs = [0,0,1,1,0,1,0,0,0], L = 3
; Bs = [0,1,0,0,1,1,0,0,0], L = 3
; Bs = [0,1,0,1,1,0,0,0,0], L = 3
; Bs = [0,1,1,0,1,0,0,0,0], L = 3
; Bs = [1,0,0,0,1,1,0,0,0], L = 3
; Bs = [1,0,0,1,1,0,0,0,0], L = 3
; Bs = [1,0,1,0,1,0,0,0,0], L = 3
; Bs = [1,1,0,0,0,0,1,0,0], L = 3
; Bs = [0,0,0,0,0,1,1,0,0], L = 2
; Bs = [0,0,0,1,0,0,1,0,0], L = 2
; Bs = [0,0,1,0,0,0,1,0,0], L = 2
; Bs = [0,1,0,0,0,0,0,1,0], L = 2
; Bs = [1,0,0,0,0,0,0,1,0], L = 2
; Bs = [0,0,0,0,0,0,0,0,1], L = 1
; false.
I have the following prolog rules.
b(b(true)) --> [true].
b(b(false)) --> [false].
b(b(E,[=],E)) --> e(E),[=],e(E).
b(b([not],B)) --> [not],b(B).
e(e(I)) --> i(I).
e(e(N)) --> n(N).
e(e(N,O,E)) --> n(N),o(O),e(E).
e(e(I,O,E)) --> i(I),o(O),e(E).
o(o(+)) --> [+].
o(o(-))--> [-].
o(o(*))--> [*].
o(o(/)) --> [/].
i(i(x)) --> [x].
i(i(y)) --> [y].
i(i(z)) --> [z].
i(i(u)) --> [u].
i(i(v)) --> [v].
n(n(0)) --> [0].
n(n(1)) --> [1].
n(n(2)) --> [2].
n(n(3)) --> [3].
n(n(4)) --> [4].
n(n(5)) --> [5].
n(n(6)) --> [6].
n(n(7)) --> [7].
n(n(8)) --> [8].
n(n(9)) --> [9].
But I dunno why
[6] 26 ?- b(A,[x,=,4],[]).
false
fails. I tried to debug the code. 4 is not getting matched with n(n(4)). I couldn't understand wat the problem is.
(You would have received an answer much earlier if you would have used the prolog tag instead)
So, how can we localize the error? Let's start with your query:
?- phrase(b(A),[x,=,4]).
false.
Bad!
Shall I really fire up a trace/debugger?
What you are currently asking is: What are the solutions for A for a well-formed sentence.
Alas, there is none.
Can't we ask Prolog a more general question?
So, dear Prolog - at least - do you know any sentence?
Please say a word!
?- phrase(b(A),L).
A = b(true), L = [true]
; A = b(false), L = [false]
; ... .
So there is something - I will remove the A, because we want to see the sentences, first.
?- phrase(b(_),L).
L = [true]
; L = [false]
; L = [x,=,x]
; L = [y,=,y]
; L = [z,=,z]
; L = [u,=,u]
; L = [v,=,v]
; L = [0,=,0]
; L = [1,=,1]
; L = [2,=,2]
; L = [3,=,3]
; L = [4,=,4]
; L = [5,=,5]
; L = [6,=,6]
; L = [7,=,7]
; L = [8,=,8]
; L = [9,=,9]
; L = [0,+,x,=,0,+,x]
; ... .
Do you see a pattern here?
Maybe we can refine this.
What are the sentences of length 3 you know of?
?- L = [_,_,_], phrase(b(_),L).
L = [x,=,x]
; L = [y,=,y]
; L = [z,=,z]
; L = [u,=,u]
; L = [v,=,v]
; L = [0,=,0]
; L = [1,=,1]
; L = [2,=,2]
; L = [3,=,3]
; L = [4,=,4]
; L = [5,=,5]
; L = [6,=,6]
; L = [7,=,7]
; L = [8,=,8]
; L = [9,=,9]
; L = [not,not,true]
; L = [not,not,false]
; false.
In other words: There are no other three word sentences than those.
Now, do you get it?
There is a rule for sentences with =:
b(b(E,[=],E)) -->
e(E),[=],e(E).
It requires that the expression on the left-hand side is the same as the expression on the right-hand side. Therefore only those sentences above.
When debugging a Prolog program, there is much less need to type (on the keyboard) test data than in other languages. Instead, use variables to let Prolog fill-in-the-variables. After all, Prolog is much faster on that than we are ; and it does not suffer CTS.
Given a CFG
S --> a S b | c | d
I wanna write a predicate like, grammar('S', sentence) which generates all possible
sentences like
sentence=acb,
sentence=acd,
sentence=c,
sentence=ab......................
Using left most derivation, if the encountered symbol is terminal it should print out that terminal, and if the encountered symbol is non terminal 'S', it should backtrack and substitute and one of the grammar a S b or c or d and repeat the process.
I dont want any code...just help me with some tips how to start with
Let's use DCGs to encode your grammar literally!
s --> [a], s, [b] | [c] | [d].
?- phrase(s,Xs).
loops. % ERROR: Out of local stack
Seems that this query does not terminate. I.e. Prolog's very simple execution strategy did not find a solution. On the other hand, think of it: Your grammar describes an infinite set of sentences. If you are enumerating an infinite set it is easy to start "at the wrong end". That's what Prolog actually does here.
But things are not that bad at all. What about enumerating all sentences of a fixed length. I will try 5:
?- length(Xs,5), phrase(s,Xs).
Xs = "aacbb"
; Xs = "aadbb"
; false.
In this case, all sentences are found and Prolog even assures us that there are no further sentences.
?- length(Xs,4), phrase(s,Xs).
false.
There are no sentences of length 4.
We can now enumerate all sentences, by length.
?- length(Xs,N), phrase(s,Xs).
Xs = "c", N = 1
; Xs = "d", N = 1
; Xs = "acb", N = 3
; Xs = "adb", N = 3
; Xs = "aacbb", N = 5
; Xs = "aadbb", N = 5
; Xs = "aaacbbb", N = 7
; ... .
What kind of derivation did we use here? Honestly, I don't know and I don't care. What is important to know is when Prolog will terminate. In this case, it will terminate, if the length is known. And that is all we need to know to guarantee that we have a fair enumeration of the infinite set. Things are even slightly better: s//0 will also terminate in cases where the length is not known like
?- Xs = [a,a,b|_], phrase(s,Xs).
false.
?- Xs = [a,a,c|_], phrase(s,Xs).
Xs = "aacbb"
; false.
?- dif(X,Y), Xs = [X,Y|_], phrase(s,Xs).
X = a, Y = c, Xs = "acb"
; X = a, Y = d, Xs = "adb"
; false.
Edit: I got some questions about the toplevel answers using "acb" for a list [a,c,b]: Please refer to this answer for an explanation and to library(double_quotes).