Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

valid bracket list in prolog

I'm trying to test if a list of brackets is valid. My code:

checkbrackets([]).
checkbrackets(['('|T]):-
    T = [')'|List],
    checkbrackets(List).    
checkbrackets(['('|T]):-
    T = ['('|List],
    append(Rest,[')'],T),
    checkbrackets(Rest).

My code works for ['(', '(', ')', '(', '(', ')', ')', ')']
but it fails for ['(', '(', ')', ')', '(', ')'].
What am I doing wrong? Is it possible to write such a test without additional arguments like counters?

like image 235
Tofu Avatar asked Dec 04 '20 21:12

Tofu


2 Answers

your append(Rest, [')'], T) will parse until the end of the list, but it is not said that the opening bracket will eventually match with the last closing bracket, for example ()() does not.

That being said, I think you make things overcomplicated. Instead of obtaining all sorts of sublists, you can use a single scan here: you use an accumulator that you initialize with 0, and the accumulator should eventually end with 0 and never be less than zero, so:

checkbrackets(B) :-
    checkbrackets(B, 0).

checkbrackets([], 0).  %% ← at the end, zero
checkbrackets([')'|T], N) :-
    N > 0,   %% ← always greater than or equal to zero.
    N1 is N-1,
    checkbrackets(T, N1).
checkbrackets(['('|T], N) :-
    N1 is N+1,
    checkbrackets(T, N1).
like image 77
Willem Van Onsem Avatar answered Nov 16 '22 03:11

Willem Van Onsem


For the sake of completeness, here is a solution without additional arguments.

checkbrackets([]).
checkbrackets(['('|Rest]):-
    append(Sub1,[')'|Sub2],Rest),
    checkbrackets(Sub1),
    checkbrackets(Sub2).

It simply follows the definition of "properly parenthesized" expression. Either it is empty, or it starts with a (, followed by a properly parenthesized subexpression (Sub1), followed by ), followed by another properly parenthesized subexpression (Sub2).

However, it is fairly inefficient as compared to the direct solution with one extra argument presented by Willem Van Onsem. The main issue is that the append/3 call needs to non-deterministically "guess" the position of the matching closing parenthesis and this generates a lot of backtracking.

like image 37
jnmonette Avatar answered Nov 16 '22 04:11

jnmonette