Related
I have been trying to convert a section of Prolog code I created to represent a basic finite automaton into a DCG. Basically it ensures that an acceptable input would be one where the third last element in a string of 0s and 1s is a 1.
E.g. [1,0,0,1,0,1] is acceptable while [1,0,1,0,0,0] is not.
accept(L) :- steps(q0,L,F), final(F).
steps(Q,[],Q).
steps(Q,[H|T],Q2) :- tran(Q,H,Qn), steps(Qn,T,Q2).
final(q1).
tran(Y,0,n0) :- Y = q0; Y = q1; Y = n0.
tran(Y,1,n1) :- Y = q0; Y = q1; Y = n0.
tran(n1,X,h1):- X = 0 ; X = 1.
tran(h1,X,q1):- X = 0 ; X = 1.
My problem is essentially with the second clause of the steps predicate where the output of "tran(Q,H,Qn)" is used as an input for steps(Qn,T,Q2), in this case being the variable Qn.
The DCG I have come up with is as follows :
accept(L) --> final(F),{F = steps(q,L)}.
steps(Q,[]) --> [Q].
steps(Q,[H|T]) --> steps(E,T), {E = tran(Q,H)}.
final(F) --> [q1], {F = q1}.
tran(Y,0) --> [n0], {Y = q;Y = q1;Y = n0}.
tran(Y,1) --> [n1], {Y = q;Y = q1;Y = n0}.
tran(n1,X) -->[h1], {X = 0; X = 1}.
tran(h1,X) -->[q1], {X = 0; X = 1}.
I am basically wondering if there is another way of ensuring that the variable E, in the second line of DCG can be used to represent tran(Q,H) instead of defining it as an extra goal which has not been working so far.
DCGs describe lists. Unlike everything else in Prolog, they describe these lists implicitly. Every value you compute in Prolog needs to be passed out of a predicate through an argument -- except for the lists described by DCGs, which you do not represent by an argument. They are instead represented as an implicit DCG state. (There are some uses for having the list as an argument as well, but it's not common.)
What this means is that when you convert a predicate to a DCG, you remove the list argument. But you must keep all other arguments so that you can communicate with the rest of the program.
So, for example, if you have the following predicate:
abc(A, B, C, [A, B, C]).
?- abc(a, b, c, ABC).
ABC = [a, b, c].
To convert it to a DCG that describes the list [A, B, C] you remove the list from the arguments but keep all other arguments:
abc(A, B, C) -->
[A, B, C].
?- phrase(abc(a, b, c), ABC).
ABC = [a, b, c].
What this means for your program is that your predicate
accept(List) :- ...
will turn into a DCG without arguments:
accept --> ...describe the list somehow...
and your steps predicate:
steps(Q, Steps, Q2) :- ...
will keep the states Q and Q2 as arguments but will remove the list argument:
steps(Q, Q2) --> ...describe the steps somehow...
With this knowledge, the first part of the translation is fairly mechanical:
accept -->
steps(q0, F),
{ final(F) }.
steps(Q, Q) -->
[].
steps(Q, Q2) -->
tran(Q, Qn),
steps(Qn, Q2).
As for the rest, you had some confusion in your transition DCG because suddenly it looked like you were trying to describe a list of states rather than a list of input symbols. This is partly because you chose bad variable names. This is not entirely your fault; many Prolog texts were written by people with a mathematical background, and written at times when books were printed on paper (which was expensive, so programs had to be more compact than anything else) or stored on tiny, slow storage devices (which again meant they had to be compact above all else) or viewed on tiny computer screens (which again meant that they had to be compact above all else). We don't have these restrictions anymore, so we can free ourselves from the shackles of the past. It is your responsibility to choose good variable names despite what outdated Prolog traditions teach you. By all of which I mean to say: If a variable describes a state, it should be called State instead of Y (or, yes, in automata theory Q can be canonical), and if a variable describes a symbol, it should be called Symbol instead of X.
Anyway. Here is a fixed version:
tran(Q, n0) --> [0], {Q = q0 ; Q = q1 ; Q = n0}.
tran(Q, n1) --> [1], {Q = q0 ; Q = q1 ; Q = n0}.
tran(n1, h1) --> [Symbol], {Symbol = 0 ; Symbol = 1}.
tran(h1, q1) --> [Symbol], {Symbol = 0 ; Symbol = 1}.
The original predicate behaves like this:
?- accept([1, 0, 0, 1, 0, 1]).
true ;
false.
?- accept([1, 0, 1, 0, 0, 0]).
false.
And the fixed DCG version behaves the same:
?- phrase(accept, [1, 0, 0, 1, 0, 1]).
true ;
false.
?- phrase(accept, [1, 0, 1, 0, 0, 0]).
false.
My impression is that you're overengineering... to keep things simple, an abstraction (DCGs, in our case) should be used for its strengths.
So, I would suggest to 'invert' your encoding schema: let's predicates be our automaton states, following input in direct way, controlled by DCG normal behaviour, and encode in predicate arguments the state payload, if any (in the example code there is none). For instance
/* File: dcg_autom.pl
Author: Carlo,,,
Created: Dec 8 2020
Purpose: https://stackoverflow.com/q/65191963/874024
*/
:- module(dcg_autom,
[accept/1
]).
accept(S) :- phrase(start, S).
start --> q0.
final --> []. % overkill, I know...
q0 --> [0], n0.
q0 --> [1], n1.
n0 --> [0], n0.
n0 --> [1], n1.
n1 --> [_], h1.
h1 --> [_], q1.
q1 --> final.
q1 --> [0], n0.
q1 --> [1], n1.
I'm suggesting this architecture change because a finite state automaton it's very easy to implement in basic Prolog, there is really no need to fiddle with DCGs...
Willing to get the list of visited states, the (boring) changes to the code could be
accept(S,L) :- phrase(start(L), S).
start([start|L]) --> q0(L).
final([final]) --> []. % overkill, I know...
q0([q0|L]) --> [0], n0(L).
q0([q0|L]) --> [1], n1(L).
n0([n0|L]) --> [0], n0(L).
n0([n0|L]) --> [1], n1(L).
n1([n1|L]) --> [_], h1(L).
h1([h1|L]) --> [_], q1(L).
q1([q1|L]) --> final(L).
q1([q1|L]) --> [0], n0(L).
q1([q1|L]) --> [1], n1(L).
and then we have
?- accept([1,0,0,1,0,1],L).
L = [start, q0, n1, h1, q1, n1, h1, q1, final] ;
false.
I've written a tail-recursive predicate in Prolog which outputs the integers between A and B in a list K. I've used "reverse" to bring the numbers into the right order:
numbers(A,B,K) :- numbers(A,B,[],K).
numbers(Y,Y,X,K) :- !, reverse([Y|X],K).
numbers(A,B,X,K) :- A<B, C is A+1, numbers(C,B,[A|X],K).
Query:
?- numbers(3,6, K).
K=[3,4,5,6]
All works fine. What I now want to do is that I only want to have odd numbers of the range between A and B in the list K. How can I do that? Thanks in advance!
Firstly, I would try to avoid using reverse/2. If you have such a solution, it's often an indicator that there's a better way to get the answer forwards more directly. Not always, but most often. reverse/2 is probably the 2nd favorite band-aid in Prolog right behind use of the cut. :)
In many problems, an auxiliary accumulator is needed. In this particular case, it is not. Also, I would tend to use CLP(FD) operations when involving integers since it's the more relational approach to reasoning over integers. But you can use the solution below with is/2, etc, if you wish. It just won't be as general.
numbers(S, E, []) :- S #> E. % null case
numbers(X, X, [X]).
numbers(S, E, [S|T]) :-
S #< E,
S1 #= S + 1,
numbers(S1, E, T).
| ?- numbers(3, 8, L).
L = [3,4,5,6,7,8] ? ;
no
| ?- numbers(A, B, [2,3,4,5]).
A = 2
B = 5 ? ;
no
| ?-
This solution avoids reverse/2 and is tail recursive.
To update it for odd integers, the first thought is that we can easily modify the above to do every other number by just adding 2 instead of 1:
every_other_number(S, E, []) :- S #> E.
every_other_number(X, X, [X]).
every_other_number(S, E, [S|T]) :-
S #< E,
S1 #= S + 2,
every_other_number(S1, E, T).
| ?- every_other_number(3, 7, L).
L = [3,5,7] ? ;
no
| ?- every_other_number(3, 8, L).
L = [3,5,7] ? ;
no
| ?- every_other_number(4, 8, L).
L = [4,6,8] ? ;
no
| ?-
Then we can do odd numbers by creating an initial predicate to ensure the condition that the first value is odd and calling every_other_number/3:
odd_numbers(S, E, L) :-
S rem 2 #= 1,
every_other_number(S, E, L).
odd_numbers(S, E, L) :-
S rem 2 #= 0,
S1 #= S + 1,
every_other_number(S1, E, L).
| ?- odd_numbers(2, 8, L).
L = [3,5,7] ? ;
no
| ?- odd_numbers(2, 9, L).
L = [3,5,7,9] ? ;
no
| ?- odd_numbers(3, 8, L).
L = [3,5,7] ? ;
no
| ?-
This could be a solution, using mod/2 operator.
numbers(A,B,K) :-
B1 is B+1,
numbers(A,B1,[],K).
numbers(Y,Y1,X,K) :-
Y = Y1,
reverse(X,K).
numbers(A,B,X,K) :-
A<B,
C is A+1,
C1 is mod(C,2),
(C1 = 0 ->
numbers(C,B,[A|X],K)
; numbers(C,B,X,K)).
Another possibility is to use DCG :
numbers(A,B,K) :-
phrase(odd(A,B), K).
odd(A,B) --> {A > B, !}, [].
odd(A,B) --> {A mod2 =:= 0, !, C is A+1}, odd(C,B).
odd(A,B) --> {C is A+2}, [A], odd(C, B).
I got a problem with lists. What I need to do is to split one list [1,-2,3,-4], into two lists [1,3] and [-2,-4]. My code looks like the following:
lists([],_,_).
lists([X|Xs],Y,Z):- lists(Xs,Y,Z), X>0 -> append([X],Y,Y) ; append([X],Z,Z).
and I'm getting
Y = [1|Y],
Z = [-2|Z].
What am I doing wrong?
If your Prolog system offers clpfd you could preserve logical-purity. Want to know how? Read on!
We take the second definition of lists/3 that #CapelliC wrote in
his answer as a starting point, and replace partition/4 by tpartition/4 and (<)/2 by (#<)/3:
lists(A,B,C) :- tpartition(#<(0),A,B,C).
Let's run a sample query!
?- As = [0,1,2,-2,3,4,-4,5,6,7,0], lists(As,Bs,Cs).
As = [0,1,2,-2,3,4,-4,5,6,7,0],
Bs = [ 1,2, 3,4, 5,6,7 ],
Cs = [0, -2, -4, 0].
As we use monotone code, we get logically sound answers for more general queries:
?- As = [X,Y], lists(As,Bs,Cs).
As = [X,Y], Bs = [X,Y], Cs = [ ], X in 1..sup, Y in 1..sup ;
As = [X,Y], Bs = [X ], Cs = [ Y], X in 1..sup, Y in inf..0 ;
As = [X,Y], Bs = [ Y], Cs = [X ], X in inf..0 , Y in 1..sup ;
As = [X,Y], Bs = [ ], Cs = [X,Y], X in inf..0 , Y in inf..0 .
Here you have. It splits a list, and does not matter if have odd or even items number.
div(L, A, B) :-
append(A, B, L),
length(A, N),
length(B, N).
div(L, A, B) :-
append(A, B, L),
length(A, N),
N1 is N + 1,
length(B, N1).
div(L, A, B) :-
append(A, B, L),
length(A, N),
N1 is N - 1,
length(B, N1).
Refer this:
domains
list=integer*
predicates
split(list,list,list)
clauses
split([],[],[]).
split([X|L],[X|L1],L2):-
X>= 0,
!,
split(L,L1,L2).
split([X|L],L1,[X|L2]):-
split(L,L1,L2).
Output :
Goal: split([1,2,-3,4,-5,2],X,Y)
Solution: X=[1,2,4,2], Y=[-3,-5]
See, if that helps.
Just for variety, this can also be done with a DCG, which is easy to read for a problem like this:
split([], []) --> [].
split([X|T], N) --> [X], { X >= 0 }, split(T, N).
split(P, [X|T]) --> [X], { X < 0 }, split(P, T).
split(L, A, B) :-
phrase(split(A, B), L).
As in:
| ?- split([1,2,-4,3,-5], A, B).
A = [1,2,3]
B = [-4,-5] ? ;
no
It also provides all the possible solutions in reverse:
| ?- split(L, [1,2,3], [-4,-5]).
L = [1,2,3,-4,-5] ? ;
L = [1,2,-4,3,-5] ? ;
L = [1,2,-4,-5,3] ? ;
L = [1,-4,2,3,-5] ? ;
L = [1,-4,2,-5,3] ? ;
L = [1,-4,-5,2,3] ? ;
L = [-4,1,2,3,-5] ? ;
L = [-4,1,2,-5,3] ? ;
L = [-4,1,-5,2,3] ? ;
L = [-4,-5,1,2,3] ? ;
(2 ms) no
Gaurav's solution will also do this if the cut is removed and an explicit X < 0 check placed in the third clause of the split/3 predicate.
There are several corrections to be done in your code.
If you enjoy compact (as readable) code, a possibility is
lists([],[],[]).
lists([X|Xs],Y,Z) :-
( X>0 -> (Y,Z)=([X|Ys],Zs) ; (Y,Z)=(Ys,[X|Zs]) ), lists(Xs,Ys,Zs).
But since (SWI)Prolog offers libraries to handle common list processing tasks, could be as easy as
lists(A,B,C) :- partition(<(0),A,B,C).
Using Prolog I'm trying to write a predicate that recognizes context free grammar and returns true if the input list matches the CFG.
The alphabet of the input consists only of a,b.
The CFG i'm trying to match is
S-> TT
T -> aTb | ab
I'm not quite sure how to implement this, mainly the T rule.
s(S0,S):-t(S0,S),t(S1,S).
t(S0,S):-S0 = a, t(S1,S), S1 = b; S0 = a, S1 = b.
match([H|T] :- s(H,T).
So if I query [a, a, b, b] it should return true.
However, I'm just getting an infinite loop.
I'm not quite sure how to implement the a^n b^n rule.
I would write the CFG in this way:
S -> T
T -> a T b | {epsilon}
that translates directly to a DCG:
s --> t.
t --> [].
t --> a, t, b.
Note I swapped the epsilon rule, to get the ability to generate phrases.
Translating that DCG by hand :
s(S0,S) :- t(S0,S).
t(S0,S0).
t(S0,S) :- S0=[a|S1], t(S1,S2), S2=[b|S].
Yields
?- phrase(s,L).
L = [] ;
L = [a, b] ;
L = [a, a, b, b] ;
L = [a, a, a, b, b, b] ;
...
I'm working on my homework for Prolog (SWI) but can't figure out how to get this done:
I have the functor:
palindrome([]).
palindrome([_]).
palindrome([A|T]) :-
append(Middle,[A],T),
palindrome(Middle).
which tells if a given list is a palindrome.
For my homework I have to write a functor palindrome/2 without append/3 and with difference lists.
I know a difference list is a form of [Y|X]-X, but I don't understand how to use this and how this can replace the append functor.
Can somebody please explain this to me?
For a given list of length n, your solution needs some O(n2) inferences: n (actually n/2) for palindrome/1 and i for each append/3 which simply searches and compares the end.
The most straight forward way to reformulate your definition uses grammars (DCGs) that are a convenient way to use difference-lists. Note that each grammar rule corresponds to a clause in your program.
palindrome -->
[].
palindrome -->
[_].
palindrome -->
[A],
palindrome,
[A].
palindrome(T) :-
phrase(palindrome,T).
For convenience, here is the same grammar written more compactly:
palindrome --> [] | [_] | [A], palindrome, [A].
Now, how are these grammar rules implemented? The easiest way is to look at the actual definition with listing(palindrome).
?- listing(palindrome).
palindrome(A, A).
palindrome([_|A], A).
palindrome([C|A], D) :-
palindrome(A, B),
B=[C|D].
So this is now your definition using difference-lists.
Just write it down yourself. You have
palindrome([]). % palindrome(Z-Z).
palindrome([_]). % palindrome([_|Z]-Z).
palindrome([A|T]) :- % palindrome([A|T]-Z):-
append(Middle,[A],T), % append(Middle-Z2,[A|Z3]-Z3,T-Z),
palindrome(Middle). % palindrome(Middle-Z2).
Append for dif-lists is append(A-B,B-C,A-C), so the append call gives us Z2=[A|Z3], Z3=Z, Middle=T, and so (writing out the two halves of a dif-list as two arguments for the predicate),
palindrome(Z,Z).
palindrome([_|Z],Z).
palindrome([A|T],Z) :-
palindrome(T, [A|Z]).
Now you can run it
10 ?- palindrome(X,[]).
X = [] ;
X = [_G340] ;
X = [_G340, _G340] ;
X = [_G340, _G346, _G340] ;
X = [_G340, _G346, _G346, _G340] ;
....
11 ?- X=[a,b,c|_],palindrome(X,[z]).
X = [a, b, c, b, a, z] ;
X = [a, b, c, c, b, a, z] ;
X = [a, b, c, _G460, c, b, a, z] ;
X = [a, b, c, _G460, _G460, c, b, a, z] ;
....
16 ?- palindrome([1,2,2,1,0],Z).
Z = [1, 2, 2, 1, 0] ;
Z = [2, 2, 1, 0] ;
Z = [0] ;
No
Of course, DCG rules provide a comfortable interface to difference-lists.