title: An easier way to split a list at the N-th place in Prolog?
body: <p>Here is a predicate to split a list into:</p>
  
  <ul>
  <li>a "front list" <code>Front</code></li>
  <li>the element at position N (0-based), <code>Element</code></li>
  <li>the "back list" <code>Back</code></li>
  </ul>
  
  <p>...so that that the original list <code>L</code>  can be recomposed with:</p>
  
  <pre><code>append([Front,[Element],Back],L).
  </code></pre>
  
  <h1>Code</h1>
  
  <pre><code>% split_list(+List, +Index, Element, Front, Back)
  
  split_list([L|Lr], N, El, [L|Front], Back) :- 
     N&gt;0,!, 
     Nm is N-1, 
     split_list(Lr,Nm,El,Front,Back).
  
  split_list([L|Lr], 0, L, [], Lr).
  </code></pre>
  
  <p>This is really hard to read. </p>
  
  <h1>Tests</h1>
  
  <pre><code>:-begin_tests(split_list).
  
  test(empty0,[fail])  :- split_list([],0,_,_,_).
  test(empty1,[fail])  :- split_list([],1,_,_,_).
  test(oorange,[fail]) :- split_list([a,b],2,_,_,_).
  test(oorange,[fail]) :- split_list([a,b],-1,_,_,_).
  test(trivial1)       :- split_list([a,b,c],0,a,[],[b,c]).
  test(trivial2)       :- split_list([a,b,c],1,b,[a],[c]).
  test(trivial3)       :- split_list([a,b,c],2,c,[a,b],[]).
  
  tt(L,X) :- 
     split_list(L,X,Element,Front,Back),
     format("~w ==&gt; ~w ~w ~w\n",[L,Front,Element,Back]),
     append([Front,[Element],Back],L).
  
  test(long1) :- 
     L=[a,b,c,d,e,f,g,h,i,j,k,l],
     length(L,Llen),
     Nmax is Llen-1,
     foreach(between(0,Nmax,X),tt(L,X)).
  
  :-end_tests(split_list).
  </code></pre>
  
  <p>We run the above:</p>
  
  <pre><code>?- run_tests(split_list).
  % PL-Unit: split_list .......
  [a,b,c,d,e,f,g,h,i,j,k,l] ==&gt; [] a [b,c,d,e,f,g,h,i,j,k,l]
  [a,b,c,d,e,f,g,h,i,j,k,l] ==&gt; [a] b [c,d,e,f,g,h,i,j,k,l]
  [a,b,c,d,e,f,g,h,i,j,k,l] ==&gt; [a,b] c [d,e,f,g,h,i,j,k,l]
  [a,b,c,d,e,f,g,h,i,j,k,l] ==&gt; [a,b,c] d [e,f,g,h,i,j,k,l]
  [a,b,c,d,e,f,g,h,i,j,k,l] ==&gt; [a,b,c,d] e [f,g,h,i,j,k,l]
  [a,b,c,d,e,f,g,h,i,j,k,l] ==&gt; [a,b,c,d,e] f [g,h,i,j,k,l]
  [a,b,c,d,e,f,g,h,i,j,k,l] ==&gt; [a,b,c,d,e,f] g [h,i,j,k,l]
  [a,b,c,d,e,f,g,h,i,j,k,l] ==&gt; [a,b,c,d,e,f,g] h [i,j,k,l]
  [a,b,c,d,e,f,g,h,i,j,k,l] ==&gt; [a,b,c,d,e,f,g,h] i [j,k,l]
  [a,b,c,d,e,f,g,h,i,j,k,l] ==&gt; [a,b,c,d,e,f,g,h,i] j [k,l]
  [a,b,c,d,e,f,g,h,i,j,k,l] ==&gt; [a,b,c,d,e,f,g,h,i,j] k [l]
  [a,b,c,d,e,f,g,h,i,j,k,l] ==&gt; [a,b,c,d,e,f,g,h,i,j,k] l []
  . done
  % All 8 tests passed
  true.
  </code></pre>
  
  <p>Ok, so it works.</p>
  
  <p>But:</p>
  
  <ol>
  <li>Is it efficient?</li>
  <li>Why isn't this in <a href="https://www.swi-prolog.org/pldoc/man?section=lists" rel="nofollow noreferrer"><code>library(lists)</code></a> for example?</li>
  <li>Maybe it is, possibly some indirect way of doing this?</li>
  </ol>
  
  <h1>Addendum</h1>
  
  <p>The predicate is barely legible.</p>
  
  <p>How about the tactical use of dicts?</p>
  
  <pre><code>split_list(L,N,Elem,Front,Back) :-
     split_list(_{list: L, index: N, element: Elem, front: Front, back: Back}).
  
  split_list(
     _{list:    [L|Lr],
       index:   N,
       element: El,
       front:   [L|Front],
       back:    Back}) :- 
     N&gt;0,!, 
     Nm is N-1, 
     split_list(
        _{list:    Lr,
          index:   Nm,
          element: El,
          front:   Front,
          back:    Back}).
  
  split_list(
     _{list:    [L|Lr],
       index:   0,
       element: L,
       front:   [],
       back:    Lr}).
  </code></pre>
  
  <p>More legible? Not sure. But it is highly likely to be slower.</p>