Search code examples
prologprolog-cut

Prolog append with cut operator


What problem can occur when we use append with cut operator?

   append2([],L,L):-!.
   append2([H|T],L,[H|TL]):-append2(T,L,TL).

I have tried several different inputs, but it always succeeds.

?- append2([1,2],[5],L).
L = [1, 2, 5].

?- append2([1,2],[1,2],L).
L = [1, 2, 1, 2].

?- append2([],[1,2],L).
L = [1, 2].

?- append2([1,2],[],L).
L = [1, 2].

Solution

  • There are two kinds of cuts; green cuts and red cuts. Green cuts are inserted just to improve efficiency and don't change the semantics of the program. Red cuts, on the other hand, do. By definition, green cuts do not cause any problems.

    So, is there any way that the behaviour would change if the cut wasn't there?

    Lets see; for the first clause to match, L1 should be unifiable with [], L2 with L and L3 with L or, in other words, L2 unifiable with L3.

    When L1 is [] the second clause cannot match; so the cut doesn't have any effect

    When L1 is not instantiated: if the length of L2 and L3 are known at this point, then they must be equal otherwise the first clause wouldn't match; thus, the second clause cannot match since at each step the length of L3 is decreased by 1 and the only way to terminate requires L2=L3

    if the length of L3 or L2 is not known: then we have a problem since the second clause may produce solutions.

    Indeed:

        3 ?- append2(L1,L2,[1,2,3]).
        L1 = [],
        L2 = [1, 2, 3].
    
        4 ?- append2(L1,[1,2,3],L3).
        L1 = [],
        L3 = [1, 2, 3].
    
        5 ?- append2(L1,L2,L3).
        L1 = [],
        L2 = L3.
    
        6 ?- append2(L1,[E1,E2],L3).
        L1 = [],
        L2 = [E1, E2].
    
        7 ?- append2(L1,L2,[E1,E2]).
        L1 = [],
        L2 = [E1, E2].
    

    while we expect:

    8 ?- append(L1,L2,[1,2,3]).
    L1 = [],
    L2 = [1, 2, 3] ;
    L1 = [1],
    L2 = [2, 3] ;
    L1 = [1, 2],
    L2 = [3] ;
    L1 = [1, 2, 3],
    L2 = [] ;
    false.
    
    9 ?- append(L1,[1,2,3],L3).
    L1 = [],
    L3 = [1, 2, 3] ;
    L1 = [_G24],
    L3 = [_G24, 1, 2, 3] ;
    L1 = [_G24, _G30],
    L3 = [_G24, _G30, 1, 2, 3] ;
    L1 = [_G24, _G30, _G36],
    L3 = [_G24, _G30, _G36, 1, 2, 3] ;
    L1 = [_G24, _G30, _G36, _G42],
    L3 = [_G24, _G30, _G36, _G42, 1, 2, 3] ;
    ...
    
    10 ?- append(L1,L2,L3).
    L1 = [],
    L2 = L3 ;
    L1 = [_G22],
    L3 = [_G22|L2] ;
    L1 = [_G22, _G28],
    L3 = [_G22, _G28|L2] ;
    ....
    
    11 ?- append(L1,[E1,E2],L3).
    L1 = [],
    L3 = [E1, E2] ;
    L1 = [_G78],
    L3 = [_G78, E1, E2] ;
    L1 = [_G78, _G84],
    L3 = [_G78, _G84, E1, E2] ;
    L1 = [_G78, _G84, _G90],
    L3 = [_G78, _G84, _G90, E1, E2] ;
    ...
    
    12 ?- append(L1,L2,[E1,E2]).
    L1 = [],
    L2 = [E1, E2] ;
    L1 = [E1],
    L2 = [E2] ;
    L1 = [E1, E2],
    L2 = [] ;
    false.