Разделить список пополам - PullRequest
8 голосов
/ 18 ноября 2011

Мне нужно определить деление так, чтобы List [1,2,3,4,5] делился на:

a = [1,2,3}

b = [4,5]

Я получаю сообщение об ошибке "Arguments are not sufficiently instantiated", и я не знаю достаточно о языке, чтобы вычислитьв чем моя проблема, или если мой дизайн даже прав.Любое руководство будет оценено.

Итак, вот что у меня есть:

append([],L2,L2).
append([H|T],L2,[H|L3]) :- append(T,L2,L3).

lengthIs([],N).
lengthIs([H|T],N) :- lengthIs(T,M), N is M+1.

divide([],[],[]).
divide([H|T],L2,L3) :-
   (  lengthIs(L2, M) < lengthIs(L1,N)/2
   -> divide(T, append(L2, H, X), L3)
   ;  divide(T, L2, append(L3,H,Y))
   ).

Ответы [ 7 ]

8 голосов
/ 18 ноября 2011

Давайте дадим предикату более реляционное имя: list_half_half/3

list_half_half(Xs, Ys, Zs) :-
   length(Xs, N),
   H is N - N // 2,
   length(Ys, H),
   append(Ys, Zs, Xs).

length/2 и append/3 предопределены практически во всех последних прологах.

Это GNU Prolog:

| ?- append(L,_,[a,b,c,d]), list_half_half(L,H1,H2).

H1 = []
H2 = []
L = [] ? ;

H1 = [a]
H2 = []
L = [a] ? ;

H1 = [a]
H2 = [b]
L = [a,b] ? ;

H1 = [a,b]
H2 = [c]
L = [a,b,c] ? ;

H1 = [a,b]
H2 = [c,d]
L = [a,b,c,d]
5 голосов
/ 18 ноября 2011

Это наиболее эффективное решение, соответствующее вашей спецификации для большинства реализаций Prolog:

divide(L, A, B) :-
    divide1(L, L, A, B).

divide1([], L, [], L).
divide1([_|T], [H|L], [H|A], B) :-
    divide2(T, L, A, B).

divide2([], L, [], L).
divide2([_|T], L, A, B) :-
    divide1(T, L, A, B).

Если вы не возражаете против того, какие элементы входят в подсписки, если они имеют одинаковую длину (как в решении из поста Константина Вайца), тогда вы можете использовать:

divide([], [], []).
divide([H|T], [H|A], B) :- divide(T, B, A).
4 голосов
/ 18 ноября 2011

append - это предопределенный предикат, поэтому может возникнуть проблема: http://en.wikibooks.org/wiki/Prolog/Lists#The_append_predicate

Вы также никогда не определяли «N» в lengthIs - вам нужно установить пустой список как 0, а не N /Вероятно, есть также функция размера

Подчеркивание говорит Прологу, что мы не заботимся об этом бите в определении предиката.

Что-то подобное должно работать

divide(L1,L2,L3):- append(L2,L3,L1), 
                   samesize(L2,L3).
divide(L1,L2,L3):- append(L2,L3,L1), 
                   onebigger(L2,L3).
samesize(A,B):-    size(A,N),
                   size(B,N).
onebigger(A,[_|T]):-   size(A,N), 
                   size(T,N).
size([],0).
size([H|T],N):-    size(T,M+1).
2 голосов
/ 18 ноября 2011

Конечно, эффект этого кода (lengthIs(L2, M) < lengthIs(L1,N)/2 -> ...) не тот, который вы ожидаете: он сравнивает не числа, а термины. Вы должны написать это так:

lengthIs(L2, M), lengthIs(L1, N), M < N/2 -> ...

Другая опечатка, похожая на ошибку: первое предложение lengthIs / 2 должно читаться как

lengthIs([],0).
2 голосов
/ 18 ноября 2011

Не нужно проверять размеры. Просто сделай это так:

div([],[],[]).
div([A],[A],[]).
div([A,B|T],[A|X],[B|Y]) :- div(T,X,Y).
0 голосов
/ 18 ноября 2011

Вот как я это сделал.Почти нет встроенных модулей:

split_list_in_half( Xs , H , T ) :-
  list_length( X , L ) ,
  LL = L - (L // 2) ,
  take_first( Xs , LL , H , T ) ,
  .

list_length( L , N ) :-
  list_length( L , 0 , N )
  .

list_length( [] , N , N ).
list_length( [X|Xs] , T , N ) :-
  T1 is T+1 ,
  list_length( Xs , T1 , N )
  .

take_first( Xs , N , Pfx , Sfx ) :-
  take_first( Xs , N , [] , P1 , Sfx ) ,
  reverse( P1 , Pfx )
  .

take_first( []     , _ , H  , H , []     ).
take_first( [X|Xs] , 0 , H  , H , [X|Xs] ).
take_first( [X|Xs] , N , H1 , H , T      ) :-
  N > 0    ,
  N1 = N-1 ,
  take_first( Xs , N1 , [X|H1] , H , T )
  .
0 голосов
/ 18 ноября 2011

Другой ответ, часто использует Backtracking, но не очень эффективен.append и length предполагаются предопределенными:

divide(A,B,C):-
    append(B,C,A),
    length(B,B_Length),
    length(C,C_Length),
    (B_Length = C_Length;
        B_Length =:= C_Length +1).

О, извините, только что увидел, что это своего рода перефразировка ответа Филиппа Уайтхауса.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...