Tree leaf traversal in Prolog - prolog

I experience some issues when I'm training prolog exercises,the problem below is,
The predicate defines what it means to be a tree, and can be used to test whether a term is a tree:
tree(t(L,R)) :- tree(L), tree(R).
tree(T) :- T\=t(_ , _).
By using this predicate you can find an element in a tree, (called a leaf):
leaf(t(L,R),E) :- leaf(L,E); leaf(R,E).
leaf(T,T) :- T\=t(_ , _).
So here have two problem, first is write predicate elements/2 that produces a list of the elements as they are found in the leafs of a tree in the first argument in a left-to-right order!
The second is write a predicate same content/2 that succeeds exactly when two trees contain the same elements in the same order! Duplicates are significant.
Hope can get anyone good at prolog can help me, thanks a lot.

Both tree/1 and leaf/1 are defaulty1,2!
Why not use a cleaner representation like this?
is_tree(leaf(_)).
is_tree(bin(L,R)) :-
is_tree(L),
is_tree(R).
Note that:
is_tree/1 is more versatile than tree/1 and leaf/1: it can generate as well as test trees—and even do a little of both (if the argument is partially instantiated).
is_tree/1 never gives logically unsound answers—no matter which "mode" it is used in.
Some sample uses of is_tree/1:
?- is_tree(T). % generate
T = leaf(_A)
; T = bin(leaf(_A),leaf(_B))
; T = bin(leaf(_A),bin(leaf(_B),leaf(_C)))
; T = bin(leaf(_A),bin(leaf(_B),bin(leaf(_C),leaf(_D))))
...
?- is_tree(bin(leaf(1),bin(leaf(2),3))). % test
false.
?- is_tree(bin(leaf(1),bin(leaf(2),leaf(3)))). % test
true.
?- T = bin(bin(leaf(1),2),_), is_tree(T). % do both (or at least try)
false.
?- T = bin(bin(leaf(1),leaf(2)),_), is_tree(T). % do both
T = bin(bin(leaf(1),leaf(2)),leaf(_A))
T = bin(bin(leaf(1),leaf(2)),bin(leaf(_A),leaf(_B)))
T = bin(bin(leaf(1),leaf(2)),bin(leaf(_A),bin(leaf(_B),leaf(_C))))
...
Coming back to your question on how to implement elements/2 and content/2... Use dcg!
leaves(leaf(E)) --> [E].
leaves(bin(L,R)) --> leaves(L), leaves(R).
same_content(A,B) :-
phrase(leaves(A),Ls),
phrase(leaves(B),Ls).
Sample query:
?- same_content(bin(leaf(1),bin(leaf(2),leaf(3))),
bin(bin(leaf(1),leaf(2)),leaf(3))).
true.
Footnote 1: This rock-solid treatise on teaching Prolog discusses many common obstacles, including defaultyness.
Footnote 2: In this answer #mat explains on how defaultyness in Prolog impedes declarative debugging and reasoning.

Related

Prolog- what causes the out of local stack error in this case?

I have a very simple program where a relation is defined between an AVL tree and a list of elements. I get correct results but after some semicolons I will receive an out of memory error, even for small inputs.
The code is not perfect as I am just trying at first to get to know the language, so it is not efficient but my question is where is the infinite loop or something similar hiding.
Only the last rule causes this problem, I tested the previous ones earlier and they worked fine.
:- use_module(library(clpfd)).
% Stuff
max(X,Y,X):- X#>=Y.
max(X,Y,Y):- Y#>X.
sub(X,Y,Z):- Z is X-Y.
append([],Ys,Ys).
append([X|Xs],Ys,[X|Zs]):-append(Xs,Ys,Zs).
% Checking "tree-ness" of a term
% is_tree(Tree)
is_tree(tree(_,Left,Right)) :-
Left=nil, Right=nil;
Left=nil, is_tree(Right);
Right=nil, is_tree(Left);
is_tree(Left), is_tree(Right).
% Computing tree height
% tree_height(Tree, Height)
tree_height(nil,0).
tree_height(tree(_,L,R),H) :-
tree_height(L,H1),
tree_height(R,H2),
H1#>=H2,
H is H1+1.
tree_height(tree(_,L,R),H) :-
tree_height(L,H1),
tree_height(R,H2),
H2#>H1,
H is H2+1.
% Checking "AVL tree-ness" of a term
% is_avl_tree(Tree, Height)
is_avl_tree_help(nil,0).
is_avl_tree_help(tree(_,L,R),H) :-
is_avl_tree_help(L,H1),
is_avl_tree_help(R,H2),
sub(H1,H2,D),
D in -1 .. 1,
max(H1,H2,H3),
H is H3+1.
is_avl_tree(Tree,H) :-
is_tree(Tree),
is_avl_tree_help(Tree,H).
% Define relation between a Tree and a List
tree_elements_help(nil,[]).
tree_elements_help(tree(X,Le,Ri),L) :-
tree_elements_help(Le,L1),
tree_elements_help(Ri,L2),
append(L1,[X|L2],L).
tree_elements(Tree,L) :-
is_tree(Tree),
tree_elements_help(Tree,L).
avl_tree_planter(Tree,L) :-
is_avl_tree(Tree,H),
tree_elements(Tree,L2),
permutation(L2,L).
The problem is that predicates like tree_elements/2 and avl_tree_planter/2 are not reversible. I assume you noticed the issue after calling avl_tree_planter/2 with its first argument uninstantiated. For example, the following queries do not terminate:
?- tree_elements(Tree,[]).
?- avl_tree_planter(Tree,[]).
I will focus on the simpler case of writing a reversible predicate inorder/2 that generates every binary tree having a given inorder traversal. The following implementation does not terminate when its first argument is uninstantiated:
inorder(leaf,[]).
inorder(node(X,L,R),L3) :-
inorder(L,L1),
inorder(R,L2),
append(L1,[X|L2],L3).
If you trace the query ?- inorder(Tree,[]) you will find that the first recursive call to inorder/2 causes the problem. In order to prove inorder(Tree,[]) it is necessary to prove infinitely many goals of the form inorder(X,[]). In general, the first recursive call to inorder/2 prevents the construction of the left subtree. This is analogous to the problem of left recursion in parsing.
Here is one solution. We introduce two arguments that track the state of the traversal. The first argument represents the input state and tracks the unprocessed elements. The second represents the output state and tracks the remaining elements. Their difference corresponds to the elements processed during a recursive call. It follows that inorder(Tree,List) should succeed with input state List and output state []. Here is one possible implementation:
inorder(Tree,List) :-
inorder(Tree,List,List,[]).
inorder(leaf,[],State,State).
inorder(node(X,L,R),List,[_|State1],State3) :-
inorder(L,Left,State1,State2),
inorder(R,Right,State2,State3),
append(Left,[X|Right],List).
For example:
?- inorder(leaf,List).
List = [].
?- inorder(node(1,leaf,leaf),List).
List = [1].
?- inorder(node(1,node(2,leaf,leaf),leaf),List).
List = [2, 1].
?- findall(Tree,inorder(Tree,[]),Trees).
Trees = [leaf].
?- findall(Tree,inorder(Tree,[1]),Trees).
Trees = [node(1, leaf, leaf)].
?- findall(Tree,inorder(Tree,[1,2]),Trees).
Trees = [node(1, leaf, node(2, leaf, leaf)), node(2, node(1, leaf, leaf), leaf)].
If this implementation reminds you of parsing, that's because it implements roughly the same functionality as the following definite clause grammar (DCG). The following code and a discussion of the relationship between nontermination and left recursion can be found at Markus Triska's DCG tutorial, which I suggest reading. Using DCG's for list processing is considered idiomatic Prolog.
:- use_module(library(dcg/basics)).
inorder(Tree,List) :-
phrase(inorder(Tree,List,_),List).
inorder(leaf,S,S) -->
[].
inorder(node(X,L,R),[_|S1],S3) -->
inorder(L,S1,S2),
[X],
inorder(R,S2,S3).
How to solve your original problem? In order to adapt these techniques to the setting of AVL trees, you need to place additional restrictions on which trees are generated (i.e., only succeed with binary search trees satisfying the AVL property). This should not be difficult. I hope you found this explanation helpful.

Prolog return a list which contains only elements which are equal to head of the list

Hello I would like to ask a doubt I have with the following code:
principio([],[]).
principio([H],[H]).
principio([H,_|_],[H]).
principio([H,H|C],P) :-
principio([H|C],R),P=[H|R].
I would like a way to get from:
?- principio([222,333,101,202,12,222,13,222],X).
X = [222,222,222]
But in this moment I get just the head:
X = [222]
So, to keep it clear I'd like: all successive occurrences of the first element as a list.
My doubt is what does this assignment P=[H|R] why not to put just:
principio([H,H|C],P) :-
principio([H|C],P)
Also, how would you try to modify this to get the result I asked for?
Thank you
Here is two ways how you can narrow down the problem. 1st, start from an unexpectedly failing query. 2nd, start from a query that should fail but rather succeeds.
1st Diagnose unexpected incompleteness
Determine a most specific failing query
?- principio([222,333,101,202,12,222,13,222],[222,222,222]).
false.
Generalize the query
... as much as possible. I could do this manually, or I could let Prolog do the work for me. Here I use library(diadem):
?- use_module(diadem).
true.
?- principio([222,333,101,202,12,222,13,222],[222,222,222]).? Gen.
Gen = principio([222, 333|_], [_, _|_])
; Gen = (dif(A100, B100), principio([A100, B100|_], [_, _|_]))
; ... .
In other words: Not only does your original query fail, but also this generalization fails! Here, we only insist that the first two elements are different, and that the resulting list contains at least two elements — no matter which!
?- dif(X, Y), principio([X,Y|_],[_,_|_]).
Generalize your program
:- op(950, fy, *).
* _P_0.
principio([], _/*[]*/).
principio([_H], _/*[H]*/).
principio([H,_|_],[H]).
principio([H,H|C],P) :-
* principio([H|C],R),
* P=[H|R].
The error must reside in the little remaining part of your program. No need to read any further!
The problem is that for a list starting with two different elements you only have the clause principio([H,_|_],[H]).. So this part has to be generalized somehow.
2nd Diagnose unexpected unsoundness
Another way of finding the error would be to start with the unexpected solution:
?- principio([222,333,101,202,12,222,13,222],[222]).
true. % incorrect !!
And then reduce the size of the query as much as possible.
?- principio([222,222],[222]).
true. % incorrect !!
Now, specialize your program inserting false as long as above query succeeds:
principio([],[]) : - false.
principio([H],[H]) :- false.
principio([H,_|_],[H]).
principio([H,H|C],P) :- false,
principio([H|C],R),
P=[H|R].
The remaining visible part is the culprit! We have to revise it. What it says is:
Any list starting with two elements corresponds to the list with the first element only.
principio([],[]).
principio([H],[H]).
principio([H,D|Xs], [H|Hs]) :-
dif(H,D),
principio([H|Xs],[H|Hs]).
principio([H,H|Xs],[H|Hs]) :-
principio([H|Xs],Hs).
In addition to the very nice answer provided by #false (+s(0)), I would point out the possibility to use DCGs for the task. They usually yield easily readable code when describing lists (see comments beside the grammar rules):
principio([H|T],Hs) :-
phrase(heads([H|T],H),Hs).
heads([],_H) --> % in the empty list
[]. % there's no element matching H
heads([H|Xs],H) --> % if the head of the list matches H
[H], % it's in the list
heads(Xs,H). % same for the tail
heads([X|Xs],H) --> % if the head of the list is
{dif(X,H)}, % different from H it's not in the list
heads(Xs,H). % same for the tail
Thus your example query yields the desired result:
?- principio([222,333,101,202,12,222,13,222],X).
X = [222,222,222] ? ;
no

Set Intersection predicate Prolog using not

I am trying to build a simple predicate which get as inputs two lists and the results is a third one consisting of the intersection of the first two.
I have decided to do using logical statement. I am pretty sure my logic is correct but my predicate is not working. Any ideas?:
element(X,[H|T]) :-
X=H
;
element(X,T).
intersection(L1,L2,R) :-
not((
element(A,L1),
not(element(A,L2))
)),
not((
element(A,L1),
not(element(A,R))
)).
Please do not post alternative methods I am wondering why this one returns FALSE every time.
Your definition is correct too general. It admits e.g. that [] is the intersection of any two lists which is too general. I.e. it incorrectly succeeds for intersection([],[a],[a]). It lacks a third "for all" idiom stating that all elements that are in both lists will be in the resulting list.
But otherwise your definition is fine. For the ground case. What is a bit unusual is that the intersection is the first and not the last argument. Quite irritating to me are the variable names. I believe that R means "result", thus the intersection. And L1 and L2 are the two sets to build the intersection.
It is a bit too general, though - like many Prolog predicates - think of append([], non_list, non_list). Apart from lists, your definition admits also terms that are neither lists nor partial lists:
?- intersection(non_list1,[1,2|non_list2],[3,4|non_list3]).
To make it really useful safe, use it like so:
?- when(ground(intersection(I, A, B)), intersection(I, A, B)).
or so:
?- ( ground(intersection(I, A, B))
-> intersection(I, A, B)
; throw(error(instantiation_error, intersection(I, A, B)))
).
Or, using iwhen/2:
?- iwhen(ground(intersection(I, A, B)), intersection(I, A, B) ).
As a minor remark, rather write (\+)/1 in place of not/1.
The problem is that not/1 merely negates the outcome of your element/2. It doesn't cause element/2 to backtrack to find other instantiations for which the enclosing not/1 will be true.
Consider the following program.
a(1).
a(2).
b(1).
b(2).
b(3).
And the following queries:
b(X), not(a(X)).
not(a(X)), b(X).
The first one yields X = 3 while the second one yields false. That is because the first query first instantiates X with 1, then with 2, then with 3, until finally not(a(X)) succeeds.
The second query first instantiates X with 1, a(1) succeeds, so not(a(1)) fails. There is no backtracking done!
The lack of backtracking due to negation as pointed out by #SQB is actually not the only problem with your code. If you play around a little with ground queries you find that non-lists and the empty list as pointed out by #false are also not the only issue. Consider the following queries:
?- intersection([2,3],[1,2,3],[2,3,4]).
yes
?- intersection([2],[1,2,3],[2,3,4]).
yes
?- intersection([3],[1,2,3],[2,3,4]).
yes
?- intersection([],[1,2,3],[2,3,4]).
yes
The first is what usually is understood as intersection. The other three are all sublists of the intersection including the trivial sublist []. This is due to the way the predicate describes what an intersection is: In an intersection is not the case that an element is in the first but not the second list AND that said element is in the first but not the third list. This description clearly fits the three above queries hence they succeed. Fooling around a little more with this description in mind there are some other noteworthy ground queries that succeed:
?- intersection([2,2,3],[1,2,3],[2,3,4]).
yes
The question whether the presence of duplicates in the solution is acceptable or not is in fact quite a matter of debate. The lists [2,2,3] and [2,3] although different represent the same set {2,3}. There is this recent answer to a question on Prolog union that is elaborating on such aspects of answers. And of course the sublists of the intersection mentioned above can also contain duplicates or multiples:
?- intersection([2,2,2],[1,2,3],[2,3,4]).
yes
But why is this? For the empty list this is quite easy to see. The query
?- element(A,[]).
no
fails hence the conjunction element(A,L1), not(element(A,L2)) also fails for L1=[]. Therefore the negation wrapped around it succeeds. The same is true for the second negation, consequently [] can be derived as intersection. To see why [2] and [3] succeed as intersection it is helpful to write your predicate as logic formula with the universal quantifiers written down explicitly:
∀L1∀L2∀R∀A (intersection(L1,L2,R) ← ¬ (element(A,L1) ∧ ¬ element(A,L2)) ∧ ¬ (element(A,L1) ∧ ¬ element(A,R)))
If you consult a textbook on logic or one on logic programming that also shows Prolog code as logic formulas you'll find that the universal quantifiers for variables that do not occur in the head of the rule can be moved into the body as existential quantifiers. In this case for A:
∀L1∀L2∀R (intersection(L1,L2,R) ← ∃A ( ¬ (element(A,L1) ∧ ¬ element(A,L2)) ∧ ¬ (element(A,L1) ∧ ¬ element(A,R))))
So for all arguments L1,L2,R there is some A that satisfies the goals. Which explains the derivation of the sublists of the intersection and the multiple occurrences of elements.
However, it is much more annoying that the query
?- intersection(L1,[1,2,3],[2,3,4]).
loops instead of producing solutions. If you consider that L1 is not instantiated and look at the results for the following query
?- element(A,L1).
L1 = [A|_A] ? ;
L1 = [_A,A|_B] ? ;
L1 = [_A,_B,A|_C] ? ;
...
it becomes clear that the query
?- element(A,L1),not(element(A,[1,2,3])).
has to loop due to the infinitely many lists L1, that contain A, described by the first goal. Hence the corresponding conjunction in your predicate has to loop as well. Additionally to producing results it would also be nice if such a predicate mirrored the relational nature of Prolog and worked the other way around too (2nd or 3rd arguments variable). Let's compare your code with such a solution. (For the sake of comparison the following predicate describes sublists of the intersection just as your code does, for a different definition see further below.)
To reflect its declarative nature lets call it list_list_intersection/3:
list_list_intersection(_,_,[]).
list_list_intersection(L1,L2,[A|As]) :-
list_element_removed(L1,A,L1noA),
list_element_removed(L2,A,L2noA),
list_list_intersection(L1noA,L2noA,As).
list_element_removed([X|Xs],X,Xs).
list_element_removed([X|Xs],Y,[X|Ys]) :-
dif(X,Y),
list_element_removed(Xs,Y,Ys).
Like your predicate this version is also using the elements of the intersection to describe the relation. Hence it's producing the same sublists (including []):
?- list_list_intersection([1,2,3],[2,3,4],I).
I = [] ? ;
I = [2] ? ;
I = [2,3] ? ;
I = [3] ? ;
I = [3,2] ? ;
no
but without looping. However, multiple occurrences are not produced anymore as already matched elements are removed by list_element_removed/3. But multiple occurrences in both of the first lists are matched correctly:
?- list_list_intersection([1,2,2,3],[2,2,3,4],[2,2,3]).
yes
This predicate also works in the other directions:
?- list_list_intersection([1,2,3],L,[2,3]).
L = [2,3|_A] ? ;
L = [2,_A,3|_B],
dif(_A,3) ? ;
L = [2,_A,_B,3|_C],
dif(_A,3),
dif(_B,3) ? ;
...
?- list_list_intersection(L,[2,3,4],[2,3]).
L = [2,3|_A] ? ;
L = [2,_A,3|_B],
dif(_A,3) ? ;
L = [2,_A,_B,3|_C],
dif(_A,3),
dif(_B,3) ? ;
...
So this version corresponds to your code without the duplicates. Note how the element A of the intersection explicitly appears in the head of the rule where all elements of the intersection are walked through recursively. Which I believe is what you tried to achieve by utilizing the implicit universal quantifiers in front of Prolog rules.
To come back to a point in the beginning of my answer, this is not what is commonly understood as the intersection. Among all the results list_list_intersection/3 describes for the arguments [1,2,3] and [2,3,4] only [2,3] is the intersection. Here another issue with your code comes to light: If you use the elements of the intersection to describe the relation, how do you make sure you cover all intersecting elements? After all, all elements of [2] occur in [1,2,3] and [2,3,4]. An obvious idea would be to walk through the elements of one of the other lists and describe those occurring in both as also being in the intersection. Here is a variant using if_/3 and memberd_t/3:
list_list_intersection([],_L2,[]).
list_list_intersection([X|Xs],L2,I) :-
if_(memberd_t(X,L2),
(I=[X|Is],list_element_removed(L2,X,L2noX)),
(I=Is,L2noX=L2)),
list_list_intersection(Xs,L2noX,Is).
Note that it is also possible to walk through the arguments of the second list instead of the first one. The predicate memberd_t/3 is a reified variant of your predicate element/2 and list_element_removed/3 is again used in the description to avoid duplicates in the solution. Now the solution is unique
?- list_list_intersection([1,2,3],[2,3,4],L).
L = [2,3] ? ;
no
and the "problem queries" from above fail as expected:
?- list_list_intersection([1,2,3],[2,3,4],[]).
no
?- list_list_intersection([1,2,3],[2,3,4],[2]).
no
?- list_list_intersection([1,2,3],[2,3,4],[3]).
no
?- list_list_intersection([1,2,3],[2,3,4],[2,2,3]).
no
?- list_list_intersection([1,2,3],[2,3,4],[2,2,2]).
no
And of course you can also use the predicate in the other directions:
?- list_list_intersection([1,2,3],L,[2,3]).
L = [2,3] ? ;
L = [3,2] ? ;
L = [2,3,_A],
dif(_A,1) ? ;
...
?- list_list_intersection(L,[2,3,4],[2,3]).
L = [2,3] ? ;
L = [2,3,_A],
dif(4,_A) ? ;
...

Appending lists in Prolog with functor

I am trying to use Prolog's append and length predicates for the first time in order to split a list, and I believe it requires a recursive solution. I am new to Prolog, and would like some help with this starter problem! :)
Here is the expected code output:
?- splits([1,2,3],S).
S = [1]/[2, 3] ;
S = [1, 2]/[3] ;
false.
It takes a list and splits it, but it does so by creating a structure with the functor /, this is what confuses me so far... I know that I need to use append for this, but how would one do so?
Here is my code so far:
splits([H | T], S) :-
length(T, len), len > 0,
It will run until the tail of the list is empty, and then stop, but I can't quite figure out how to add in the append function or make it recursive... Could someone give me a tip? :)
I would say that you are almost at a working implementation with your remark that append/3 can be used for splitting lists. This is indeed what append/3 in the instantiation (-,-,+) does.
The only added requirement that seems to occur in your question is to exclude cases in which either of the splits is empty. This can be achieved by checking for inequivalence between terms using \==/2.
This results in the following code:
splits(List, X/Y):-
append(X, Y, List),
X \== [],
Y \== [].
PS: Notice that your use of len in your code snippet is wrong, since len is not a Prolog variable but an atom. Handing an atom to the second argument of length/2 produces a type error, and an arithmetic error in len > 0 (provided that len is not defined as a function). (Both observations relate to SWI-Prolog.)
Hope this helps!
Here is a recursive approach:
splits([A,B|T], [A]/[B|T]).
splits([A|T], [A|R]/S) :-
splits(T, R/S).
The first clause provides the base case of splitting a list with at least 2 elements ([A,B|T]) into [A]/[B|T] (it just splits out the first element).
The second clause says that [A|R]/S is the split of [A|T] if R/S is the split of T. So it will "generate" the other solutions recursing down to the base case. If the first list has only two elements, the base case will be successful, and backtrack to the recursive case will fail on the first try (which is what you want - no more solutions to that case) because the recursive case only succeeds when the first list has 3 or more elements (A plus the two enforced on T in the recursive query).
| ?- splits([1], S).
no
| ?- splits([1,2], S).
S = [1]/[2] ? ;
no
| ?- splits([1,2,3], S).
S = [1]/[2,3] ? ;
S = [1,2]/[3] ? ;
no
...

Prolog dcg generating all words from language

I'm trying to write some dcg grammar in prolog which will describe language of
a^nb^n n>=0
"",ab,aabb,aaabbb itd
All what I wrote is
s --> slowo.
slowo --> [a],slowo,[b],!.
slowo --> [].
And its good as long as all I want to do is just check if word is correct, but how should dcg grammar look in prolog for ?-phrase(s,X) which will generate all words from my language?
In addition to #Mog's answer, let us consider the more general case:
What, if the grammar is so complex, that reordering DCG-rules will not help? How can we still enumerate all sentences? If the grammar is formulated in such a manner, that it terminates for a fixed length, we get all sentences with
?- length(Xs, N), phrase(s, Xs).
The goal length alone will enumerate all lists in a fair manner. That is, starting with the shortest [] all lists are enumerated:
?- length(Xs, N).
Xs = [], N = 0
; Xs = [_A], N = 1
; Xs = [_A,_B], N = 2
; Xs = [_A,_B,_C], N = 3
; Xs = [_A,_B,_C,_D], N = 4
; ... .
And now, the length being fixed, the goal phrase(s, Xs) will find all answers for that fixed length. As an example, look at Mat's answer to this grammar.
So this is a general method to inspect a grammar's sentences. However - there is a price to pay for this generality! For grammars with finitely many sentences, out method will not terminate:
:- use_module(library(double_quotes)).
s --> "a"|"b".
?- phrase(s, Xs).
Xs = "a"
; Xs = "b".
This grammar works out of the box, but together with length/2 we get now:
?- length(Xs, N),phrase(s, Xs).
Xs = "a", N = 1
; Xs = "b", N = 1
; loops.
This method is often called iterative deepening, although this term more precisely imposes a bound to the depth of the derivation. But we are imposing a bound to the actual "output". So iterative deepening is also able to handle left-recursion, whereas length/2 works only for grammars that terminate for a fixed input length.
What makes this technique so particularly interesting in Prolog is that it meshes perfectly with Prolog's chronological backtracking mechanism.
If you're beginning with Prolog, try to avoid the use of !/0. You can generally do better without it.
Here for example, your grammar could be written as follows:
s --> [].
s --> [a], s, [b].
and queried as follows:
?- phrase(s, X).
Note that prolog clauses are picked from left to right and top to bottom, so a rule written at the top of another one will be prioritized when the backtracking is involved.
In SWI Prolog, I could use:
s(X, []).
or
phrase(s, X).
(as you suggested) to get all of the strings. In order for that to produce any answers without a stack overflow, however, I needed to reverse the order of the two rules for slowo and remove the cut from the recursive rule.

Resources