# 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).
``````