Reordering constraints to ensure instantiated variables

Hi!

I’m attempting to write a relation that maps between a string and the parsed version of that string. The string looks like

//4/////2/1//3///1/4///2///1/3//2

And should be interpreted as a list delimited by /, where an empty element means something (denotes a free variable), and an integer (0-9) denotes a variable with such integer value. But I haven’t gotten that far yet.

After taking some code from online and modifying it, I arrived at the following:

nonmember(Arg,[Arg|_]) :-
  !,
  fail.
nonmember(Arg,[_|Tail]) :-
  !,
  nonmember(Arg,Tail).
nonmember(_,[]).

split(In, Sep, [Left|Rest]) :-
  append(Left, [Sep|Right], In), nonmember(Sep, Left), split(Right, Sep, Rest).
split(In, Sep, [In]) :- nonmember(Sep, In).

This seems to work:

?- split(S, 47, [[], [50], []]).

S = [47,50,47]

?- split("2//3", 47, C).

C = [[50],[],[51]] ?

But I also want to “chunk” them into 4 equal pieces:

chunk_n(N, [], []).
chunk_n(N, L, [Chunk | Chunked]) :-
  append(Chunk, L1, L),
  length(Chunk, N),
  chunk_n(N, L1, Chunked).

urlcounts(N, UrlCounts, Top, Bottom, Left, Right) :-
  chunk_n(N, L, [Top, Bottom, Left, Right]),
  split(UrlCounts, 47, L).

urlcounts is my overall function.

However, urlcounts behaves as the following:

  1. if the chunk_n(...) condition is put before the split(...) one, then it only works when Top Bottom Left Right are instantiated and stack overflows if UrlCounts is instantiated but not Top Bottom Left Right
  2. if split(...) before chunk_n(...), then it only works if UrlCounts is instantiated, and stack overflows if Top Bottom Left Right are given but not UrlCounts.

Any suggested fixes?

That nonmember looks fundamentally flawed. Here’s a slight tweak (added the first pass) to my member_other, to use instead:

% The list is treated as a set
member_other(Elem, Lst, Member) :-
    % Scan list for equal match, as first pass
    (   member(E, Lst),
        Elem == E
    ->  Member = member(Elem)
    ;   member_other_(Lst, Elem, [], Member)
    ).
    
% Can be other
member_other_([], Elem, DL, other(Elem)) :-
    % Have delayed adding attributes to Elem, for performance
    maplist(dif(Elem), DL).
member_other_([H|T], E, DL, M) :-
    (   H \= E
        % Fast failure, no need for dif
    ->  member_other_(T, E, DL, M)
        % Unsure
    ;   member_other_eq_(M, T, H, E, DL)
    ).

member_other_eq_(member(E), _, E, E, _).
member_other_eq_(M, T, H, E, DL) :-
    member_other_(T, E, [H|DL], M).

Example:

?- member_other(X, [1, 2], M).
X = 1,
M = member(1) ;
X = 2,
M = member(2) ;
M = other(X),
dif(X, 2),
dif(X, 1).