def next_to_in(E1: Term, E2: Term, Es: SuperSequence): """ Are E1 and E2 are next to each other in Es. """ for _ in forany([ lambda: is_contiguous_in([E1, E2], Es), lambda: is_contiguous_in([E2, E1], Es), ]): yield
def append(Xs: Union[LinkedList, Var], Ys: Union[LinkedList, Var], Zs: Union[LinkedList, Var]): """ append([], Ys, Zs). append([X|Xs], Ys, [X|Zs]) :- append(Xs, Ys, Zs). Note that this could just have well have been written: append([Z|Xs], Ys, [Z|Zs]) :- append(Xs, Ys, Zs). or append([W|Xs], Ys, [W|Zs]) :- append(Xs, Ys, Zs). We don't have to implicitly favor the Xs. No matter what the variable is called, this is really unifying Xs_head and Zs_head. append/3 converts between: Xs + Ys <--> Zs It does this by moving elements between the Xs and the Zs. If we are moving from Zs to Xs + Ys, there will be multiple answers depending on how much of Zs is shifted before we let Ys be the rest. The function consists of two "clauses" (see prolog definition above), which are tried in sequence. Clause 1 This is the step in which we set Xs to [] and set Ys to Zs. No recursive call. At this point, earlier recursion calls will have shifted elements between Xs and Zs. But those are not visible at this level. Clause 2. The recursive step. Move an element between Xs and Zs and call append recursively with Xs_Tail and Zs_Tail. Since an empty list cannot unify with a LinkedList that has a head and a tail, if either Xs or Zs is empty, unify_pairs will fail. The actual code is quite short. It's very similar to like the prolog code. """ # Create the existential variables at the start. (XZ_Head, Xs_Tail, Zs_Tail) = n_Vars(3) for _ in forany([ # Clause 1. lambda: unify_pairs([(Xs, emptyLinkedList), (Ys, Zs)]), # Clause 2. lambda: forall([ lambda: unify_pairs([(Xs, LinkedList((XZ_Head, Xs_Tail))), (Zs, LinkedList((XZ_Head, Zs_Tail)))]), lambda: append(Xs_Tail, Ys, Zs_Tail) ]) ]): yield
def is_a_subsequence_of(As: List, Zs: SuperSequence): """ As may be spread out in Zs but must be in the same order as in Zs. """ if not As: # If no more As to match, we're done. Succeed. yield elif not Zs: # If no more Zs to match the remaining As, fail. return else: for _ in forany([ # Match As[0] and Zs[0]; go on to is_a_subsequence_of(As[1:], Zs[1:]) lambda: forall([lambda: unify(As[0], Zs[0]), lambda: is_a_subsequence_of(As[1:], Zs[1:])]), # Whether or not we matched As[0] and Zs[0] above, try is_a_subsequence_of(As, Zs[1:]) lambda: is_a_subsequence_of(As, Zs[1:]) ]): yield