Пролог: разбить список на список из N списков, содержащих по N элементов каждый

Я искал множество существующих вопросов о Прологе, касающихся SO, имеющих отношение к расщеплению, но не смог найти такой общий, как тот, который я хочу. Я хотел бы отметить, что мне удалось разделить списки на списки из 2/3/4 элементов, используя 2/3/4 переменные, переданные перед переменной списка. Этот вопрос отличается от этого только своей универсальностью.

Таким образом, мой список всегда будет содержать N*N элементов, причем N заранее неизвестно (обычно они варьируются от 4 до 36, да, N также является идеальным квадратом). Я хочу разделить его на список из N списков, каждый из которых содержит N элементов, потому что это позволит мне рассматривать его как матрицу, что позволяет транспонировать и выполнять определенные операции такого рода. Я действительно не смог зайти слишком далеко с логикой, потому что я относительно новичок в декларативном программировании; см. ниже мою неполную (ошибочную) попытку:

listmodel(1,L):- L = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16].
size(L,N) :- length(L,N1), N is round(sqrt(N1)).

% add_tail(+Liste, +Element, -ResultantList)
add_tail([],L,[L]).
add_tail([X|L1],L2,[X|LI]):-add_tail(L1,L2,LI).

% partition the list containing N*N items into a list of N lists containing N elements each.
% part(+Liste, +Size, -ResultantList)
part([],_,DL).
part(L,N,DL) :-
    length(P,N), % P(refix) initialized
    append(P,S,L), % S(uffix) contains rest of L, using append in (-,-,+) mode
    add_tail(DL,P,DL1), %add P(first N elements) as first element of DL.
    part(S,N,DL1).

Сейчас работает ?- listmodel(1,L),size(L,N),part(L,N,DL). будет производить DL=[] потому что это то, что он инициализируется в первом add_tail позвонить в part сказуемое. Кажется, я не могу понять, как сохранить все элементы в списке, который сохранился с помощью рекурсии.

Любая помощь / направление любого рода будут оценены. Я застрял здесь более 23 часов 10 минут.

Благодарю.

2 ответа

Решение

Это должно сделать это:

часть([], _, []).
часть (L, N, [DL|DLTail]):-
   длина(DL, N),
   добавить(DL, LTail, L),
   часть (LTail, N, DLTail).

Базовый случай - первый / последний аргументы - пустые списки.

Рекурсивный шаг берет новый список из N элементов, берет первые N элементов из L (который будет одним из элементов третьего аргумента) и вызывает рекурсивно.

Хотите совместить универсальность и выгодные свойства терминации? Используйте clpfd!

: - use_module ( библиотека (clpfd)).

Сначала мы определяем list_prefix_n_suffix/4, list_prefix_n_suffix(Zs,Xs,N,Ys) логически эквивалентно обоим append(Xs,Ys,Zs), length(Xs,N) а также length(Xs,N), append(Xs,Ys,Zs), но имеет лучшее универсальное поведение завершения, чем 1!

list_prefix_n_suffix (Zs, Xs, N, Ys): -
   list_prefix_n0_n_suffix (Zs, Xs, 0, N, Ys).

list_prefix_n0_n_suffix (Zs, Xs, N0, N, Ys): -
   zcompare (Order, N0, N),
   rel_list_prefix_n0_n_suffix (Порядок, Zs, Xs, N0, N, Ys).

rel_list_prefix_n0_n_suffix (=, Ys, [], _, _, Ys).
rel_list_prefix_n0_n_suffix (<, [Z | Zs], [Z | Xs], N0, N, Ys): -
   N1 # = N0 + 1,
   list_prefix_n0_n_suffix (Zs, Xs, N1, N, Ys).

Некоторые примеры запросов для list_prefix_n_suffix/4:

? - list_prefix_n_suffix ([a, b, c], Xs, -1, Ys). ложь % OK: слишком мало?- list_prefix_n_suffix([a,b,c], Xs, 0, Ys).
Xs = [], Ys = [a,b,c].                                          % успешно определен? - list_prefix_n_suffix ([a, b, c], Xs, 4, Ys). ложь % OK: слишком большой?- list_prefix_n_suffix([a,b,c], Xs, N, Ys).
   Xs = [], N = 0, Ys = [a,b,c];  Xs = [a], N = 1, Ys =   [b,c];  Xs = [a,b], N = 2, Ys =     [c];  Xs = [a,b,c], N = 3, Ys =      []; ложный. % завершается повсеместно 

На основании выше list_prefix_n_suffix/4 мы определяем list_rows_width/3:

list_rows_width ([], [], _N).
list_rows_width ([E | Es0], [[R | Rs] | Rss], N): -
   list_prefix_n_suffix ([E | Es0], [R | Rs], N, Es),
   list_rows_width (Es, Rss, N).

Примеры запросов с использованием list_rows_width/3:

? - list_rows_width ([a, b, c, d, e, f], Rows, 4).
ложный. % ОК: 6 не делится на 4?- list_rows_width([a,b,c,d,e,f], Rows, 3).
Строки = [[a,b,c],[d,e,f]].                       % преуспевает детерминистически?- list_rows_width([a,b,c,d,e,f,g,h,i,j,k,l], Rows, N).
   N =  1, Rows = [[a],[b],[c],[d],[e],[f],[g],[h],[i],[j],[k],[л]];  N =  2, Rows = [[a,  b],[c,  d],[e,  f],[g,  h],[i,  j],[k,  l]];  N =  3, Rows = [[a,  b,  c],[d,  e,  f],[g,  h,  i],[j,  k,  l]];  N =  4, Rows = [[a,  b,  c,  d],[e,  f,  g,  h],[i,  j,  k,  l]];  N =  6, Rows = [[a,  b,  c,  d,  e,  f],[g,  h,  i,  j,  k,  l]];  N = 12, ряды = [[a,  b,  c,  d,  e,  f,  g,  h,  i,  j,  k,  l]]; ложный. % завершается повсеместно

Работает так, как должно!


Сноска 1: Не прибегая к использованию альтернативных механизмов управления потоком, таких как пролог-сопрограммирование.

Другие вопросы по тегам