Next filter out obviously invalid positions (by invalid, I mean, that x__
must end before y__?IntegerQ
ends and z__
must begin after y__?IntegerQ
starts):
This answer willNow is the tricky part which may be temporarily deletedvulnerable to "algorithmic explosion". From this list of positions I wish to select permissible end-points of every pattern.
pos = pos~Join~{Length[args] + 1};
Do[pos[[i]] = Cases[pos[[i]], Alternatives @@ (pos[[i + 1]] - 1)], {i, Length[pos] - 1}];
pos = Most@pos
(* {{100, 101}, {101, 102}, {200}} *)
Tuples@%
(* {{100, 101, 200}, {100, 102, 200}, {101, 101, 200}, {101, 102, 200}} *)
Select[%, # === Union@# &]
(* {{100, 101, 200}, {100, 102, 200}, {101, 102, 200}} *)
Let's return the possible ways the original pattern can match our symbol args
:
Internal`PartitionRagged[args, Differences[{0}~Join~#]] & /@ %
(*{
{{..., 100.}, {101}, {102, 103., 104., ...}},
{{..., 100.}, {101, 102}, {103., 104., ...}},
{{..., 100., 101}, {102}, {103., 104., ...}}
}
*)
So by precomputing 200 tests it was possible to somewhat analytically reduce the number of combinations of arguments to 3, pending some incremental step in its writingrather than 14752 calls to IntegerQ
.
This guide should work for any amount of BlankSequence
but there's a lot of bulletproofing to do here as well as early detection of outright non-matches. Hopefully, this can be a starting point for further efforts.