Split list

You could take advantage of the Rest argument of phrase/3; and there is also sequence//2 from library(dcg/high_order). It would be enough to define:

length_list(N, L) -->
    { length(L, N) },
    L. % yes don't need string//1

Then:

?- use_module(library(dcg/high_order)).
true.

?- phrase(sequence(length_list(2), Sublists), [a,b,c,d], Rest), !.
Sublists = [[a, b], [c, d]],
Rest = [].

?- phrase(sequence(length_list(2), Sublists), [a,b,c,d,e], Rest), !.
Sublists = [[a, b], [c, d]],
Rest = [e].

But of course it all depends on the use case.

EDIT: since there are some “likes” on this, I would like to point out two issues.

  1. As it stands, using L instead of string(L) is indeed a bit slower.
  2. Since sequence//2 leaves choice points, it will eventually run out of memory if the list we are parsing is long enough. Cutting on every matched prefix will avoid this.
3 Likes