Prolog - Generate alternating symbols on backtrack: [a] ; [a,b]; [a,b,a]; [a,b,a,b]
Asked Answered
J

3

6

I've wrapped my mind a lot and couldn't figure it out. Is it possible to make a script that with backtrack generates lists in this format:

[a]
[a,b]
[a,b,a]
[a,b,a,b]
...

I've made one that generates two elements at a time but my head started to hurt trying to make one that generates "a" and the next time "b" and the next "a" and so on.

Here is the script for two elements at a time:

ab([a]).
ab([b,a|T]):-ab([a|T]).
ab([a,b|T]):-ab([b|T]).
Janice answered 18/1, 2017 at 19:2 Comment(0)
M
8

When describing lists, always consider using DCG notation.

This makes it very convenient to focus an the essence of what you want to describe, without so many additional variables and arguments.

For example, consider:

abs --> [a], abs_rest.

abs_rest --> [].
abs_rest --> [b], ( [] | abs ).

Sample query and answer:

?- phrase(abs, ABs).
ABs = [a] ;
ABs = [a, b] ;
ABs = [a, b, a] ;
ABs = [a, b, a, b] ;
ABs = [a, b, a, b, a] ;
ABs = [a, b, a, b, a, b] .

See for more information about this convenient formalism!

Medamedal answered 18/1, 2017 at 19:8 Comment(5)
Thanks! That is interesting, did not stumble upon it before and we certainly don't learn it in our course in my university, it's valuable information! Anyway I am training my recursion kills and making generating scripts and I am not sure if DCGs will be accepted on my exam so I am still searching for a solution in the traditional way :)Janice
If by "in the traditional way", you mean "in a less readable way", simply use the following query to get plain Prolog code corresponding to the DCG: ?- listing(abs//0), listing(abs_rest//0). You can take its output, hand it to your instructor, and know that there is a better solution that you probably are not allowed to use, because why use a fitting formalism when there is a more complex way to express the same thing too?Medamedal
Traditional wasn't the most suitable word to describe what I need. I am trying to figure it out written only using Head, Tail and recursion properties of the lists. In such fashion: ab([a]). ab([b,a|T]):-ab([a|T]). ab([a,b|T]):-ab([b|T]).Janice
As I said: Load the DCG above, and then use listing/1 to make your Prolog system output the lower-level code that you can use as well. Internally, your system compiles the DCG down to plain Prolog, and you can inspect the generated code with listing/1 (if your system provides it).Medamedal
Thanks mat! Seems I was kind of tired already yesterday and didn't catch that the first time, everything is clear now :)Janice
L
4

I agree with @mat that one should use when possible for these type of problems.

Here is a different set of rules.

abs --> [a].
abs --> [a,b].
abs --> [a,b], abs.

?- phrase(abs, Ls).
Ls = [a] ;
Ls = [a, b] ;
Ls = [a, b, a] ;
Ls = [a, b, a, b] ;
Ls = [a, b, a, b, a] ;
Ls = [a, b, a, b, a, b] ;
Ls = [a, b, a, b, a, b, a] ;
Ls = [a, b, a, b, a, b, a, b] ;
Ls = [a, b, a, b, a, b, a, b, a] 

Interestingly those rules started from this variation

abs2 --> [].
abs2 --> [a].
abs2 --> [a,b], abs2.

?- phrase(abs2, Ls).
Ls = [] ;
Ls = [a] ;
Ls = [a, b] ;
Ls = [a, b, a] ;
Ls = [a, b, a, b] ;
Ls = [a, b, a, b, a] ;
Ls = [a, b, a, b, a, b] ;
Ls = [a, b, a, b, a, b, a] ;
Ls = [a, b, a, b, a, b, a, b] 

which is one of the exercises from Using Definite Clause Grammars in SWI-Prolog

If you prefer not to use DCG, then I agree with @mat and suggest that you use listing/1 to see the DCG in standard Prolog syntax.

listing(abs).

abs([a|A], A).
abs([a, b|A], A).
abs([a, b|A], B) :-
        abs(A, B).

listing(abs2).  

abs2(A, A).
abs2([a|A], A).
abs2([a, b|A], B) :-
        abs2(A, B).

As normal Prolog rules they can be used as such:

abs(X,[]).
X = [a] ;
X = [a, b] ;
X = [a, b, a] ;
X = [a, b, a, b] ;
X = [a, b, a, b, a] ;
X = [a, b, a, b, a, b] ;
X = [a, b, a, b, a, b, a]

abs2(X,[]).
X = [] ;
X = [a] ;
X = [a, b] ;
X = [a, b, a] ;
X = [a, b, a, b] ;
X = [a, b, a, b, a] ;
X = [a, b, a, b, a, b] 
Larena answered 18/1, 2017 at 20:38 Comment(3)
The text you link to uses outdated terminology, please use a better maintained document.Medamedal
@Medamedal I take it you are referring to, Using Definite Clause Grammars in SWI-Prolog. I added the link for that to show that there are other similar problems, that's basically the reason for the link.Larena
Thanks mate, for further explaining this, appreciated!Janice
B
1

The predicate you wrote is too general:

?- ab([b,a]).
true

The cause is the following rule

ab([b,a|T]) :-
  ab([a|T]).

One could say that you describe an intermediate result which is no solution to your actual problem. To fix this, you could state than an ab sequence starts with a and the rest bust be a ba sequence, where ba sequences are again defined in terms of ab sequences:

ab([a]).
ab([a|Xs]) :-
    ba(Xs).

ba([b]).
ba([b|Xs]) :-
    ab(Xs).

Alternatively, you could think of abs as a state machine which produces a whenever the last element was b and vice versa. If we introduce an additional argument to trace the history, we arrive at:

abs(a,[a]).
abs(b,[b]).
abs(a,[a|Xs]) :-
    abs(b,Xs).
abs(b,[b|Xs]) :-
    abs(a,Xs).

Now we define an ab sequence as one which last prepended an a:

ab(Xs) :-
    abs(a,Xs).

Have fun :)

Bourgeoisie answered 19/1, 2017 at 12:58 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.