Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>This question is rather old, but I'll post my solution anyways. I'm learning prolog in my spare time, and found this quite a challenging problem.</p> <p>I learned a lot about DCG and difference lists. I'm afraid, I didn't come up with a solution that does not use lists. Like mat suggested, it transforms terms into flat lists to cope with the parentheses, and uses <code>permutation/2</code> to match the lists, accounting for the commutative nature of the ++ operator...</p> <p>Here's what I came up with:</p> <pre><code>:- op(900, yfx, equ). :- op(800, xfy, ++). check(A equ B) :- A equ B. equ(A,B) :- sum_pp(A,AL,Len), sum_pp(B,BL,Len), !, permutation(AL, BL). sum_pp(Term, List, Len) :- sum_pp_(Term, List,[], 0,Len). sum_pp_(A, [A|X],X, N0,N) :- nonvar(A), A\=(_++_), N is N0+1. sum_pp_(A, [A|X],X, N0,N) :- var(A), N is N0+1. sum_pp_(A1++A2, L1,L3, N0,N) :- sum_pp_(A1, L1,L2, N0,N1), (nonvar(N), N1&gt;=N -&gt; !,fail; true), sum_pp_(A2, L2,L3, N1,N). </code></pre> <p>The <code>sum_pp/3</code> predicate is the workhorse which takes a term and transforms it into a flat list of summands, returning (or checking) the length, while being immune to parentheses. It is very similar to a DCG rule (using difference lists), but it is written as a regular predicate because it uses the length to help break the left recursion which would otherwise lead to infinite recursion (took me quite a while to beat it).</p> <p>It can check ground terms:</p> <pre><code>?- sum_pp(((a++b)++x++y)++c++d, L, N). L = [a,b,x,y,c,d], N = 6 ; false. </code></pre> <p>It also generates solutions:</p> <pre><code>?- sum_pp((b++X++y)++c, L, 5). X = (_G908++_G909), L = [b,_G908,_G909,y,c] ; false. ?- sum_pp((a++X++b)++Y, L, 5). Y = (_G935++_G936), L = [a,X,b,_G935,_G936] ; X = (_G920++_G921), L = [a,_G920,_G921,b,Y] ; false. ?- sum_pp(Y, L, N). L = [Y], N = 1 ; Y = (_G827++_G828), L = [_G827,_G828], N = 2 ; Y = (_G827++_G836++_G837), L = [_G827,_G836,_G837], N = 3 . </code></pre> <p>The <code>equ/2</code> operator "unifies" two terms, and can also provide solutions if there are variables:</p> <pre><code>?- a++b++c++d equ c++d++b++a. true ; false. ?- a++(b++c) equ (c++a)++b. true ; false. ?- a++(b++X) equ (c++Y)++b. X = c, Y = a ; false. ?- (a++b)++X equ c++Y. X = c, Y = (a++b) ; X = c, Y = (b++a) ; false. </code></pre> <p>In the equ/2 rule</p> <pre><code>equ(A,B) :- sum_pp(A,AL,Len), sum_pp(B,BL,Len), !, permutation(AL, BL). </code></pre> <p>the first call to sum_pp generates a length, while the second call takes the length as a constraint. The cut is necessary, because the first call may continue to generate ever growing lists that will never again match with the second list, leading to infinite recursion. I haven't found a better solution yet...</p> <p>Thanks for posting such an interesting problem!</p> <p>/Peter</p> <p>edit: sum_pp_ written as DCG rules:</p> <pre><code>sum_pp(Term, List, Len) :- sum_pp_(Term, 0,Len, List, []). sum_pp_(A, N0,N) --&gt; { nonvar(A), A\=(_++_), N is N0+1 }, [A]. sum_pp_(A, N0,N) --&gt; { var(A), N is N0+1 }, [A]. sum_pp_(A1++A2, N0,N) --&gt; sum_pp_(A1, N0,N1), { nonvar(N), N1&gt;=N -&gt; !,fail; true }, sum_pp_(A2, N1,N). </code></pre> <p>update:</p> <pre><code>sum_pp(Term, List, Len) :- ( ground(Term) -&gt; sum_pp_chk(Term, 0,Len, List, []), ! % deterministic ; length(List, Len), Len&gt;0, sum_pp_gen(Term, 0,Len, List, []) ). sum_pp_chk(A, N0,N) --&gt; { A\=(_++_), N is N0+1 }, [A]. sum_pp_chk(A1++A2, N0,N) --&gt; sum_pp_chk(A1, N0,N1), sum_pp_chk(A2, N1,N). sum_pp_gen(A, N0,N) --&gt; { nonvar(A), A\=(_++_), N is N0+1 }, [A]. sum_pp_gen(A, N0,N) --&gt; { var(A), N is N0+1 }, [A]. sum_pp_gen(A1++A2, N0,N) --&gt; { nonvar(N), N0+2&gt;N -&gt; !,fail; true }, sum_pp_gen(A1, N0,N1), { nonvar(N), N1+1&gt;N -&gt; !,fail; true }, sum_pp_gen(A2, N1,N). </code></pre> <p>I split sum_pp into two variants. The first is a slim version that checks ground terms and is deterministic. The second variant calls <code>length/2</code> to perform some kind of iterative deepening, to prevent the left-recursion from running away before the right recurson gets a chance to produce something. Together with the length checks before <em>each</em> recursive call, this is now infinite recursion proof for many more cases than before.</p> <p>In particular the following queries now work:</p> <pre><code>?- sum_pp(Y, L, N). L = [Y], N = 1 ; Y = (_G1515++_G1518), L = [_G1515,_G1518], N = 2 . ?- sum_pp(Y, [a,b,c], N). Y = (a++b++c), N = 3 ; Y = ((a++b)++c), N = 3 ; false. </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload