2011-11-18 90 views
8

我需要让列表[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)) 
    ). 
+2

对于'div([1,2,3,4,5],[1,2,3],[4,5]),您检查为答案的解决方案失败。 ' – false

回答

8

让我们给谓词多个关系名字: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/2append/3在几乎所有最近Prologs是预定义的。

这是GNU序言:

| ?- 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] 
+1

+1使用'length/2'创建骨架结果列表。 –

4

追加是一个预先定义的谓语,所以这可能是这个问题:http://en.wikibooks.org/wiki/Prolog/Lists#The_append_predicate

还从来没有在lengthIs定义“N” - 你需要将空列表设置为0,而不是N/ 还有可能还有尺寸函数

下划线告诉Prolog我们不关心那个谓词定义中的那个位。

像这样的东西应该工作

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

不需要检查大小。只要像这样做:

div([],[],[]). 
div([A],[A],[]). 
div([A,B|T],[A|X],[B|Y]) :- div(T,X,Y). 
+2

请注意,此解决方案并不符合OP规范,因为它使用'div([1,2,3,4,5],[1,3,5],[2,4])'而不是'div ([1,2,3,4,5],[1,2,3],[4,5])'。 – salva

+2

@KonstantinWeitz:将[1,2,3,4,5]'分成'[1,3,5]'和'[2,4]'。它将它分成两个正确长度的列表,但不是正确的*内容*。 –

2

代码(lengthIs(L2, M) < lengthIs(L1,N)/2 -> ...)的必经之效果不是你所期望的:它不比较数字,但条款。你应该写这样说:

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

像错误另错字:lengthIs/2的第一句应改为

lengthIs([],0). 
5

这是符合你的规格对于大多数的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). 

如果你不介意的元素进入子列表,只要它们是相似的长度(如从康斯坦丁·韦茨后的溶液),然后你CA氮利用:

divide([], [], []). 
divide([H|T], [H|A], B) :- divide(T, B, A). 
+1

如果第一个或第二个列表的长度已知,则您的解决方案终止。因此'除(L,A,B)终止_边界(L); (A).'但它仍然不会终止'divide(L,A,[])。'这里预计会有两个答案! 'L = [],A = []; L = [X],A = [X]' – false

+0

是的,该谓词预计被用作'divide(+, - , - )'。 – salva

+1

你比'+, - ,'更好!有'分(L,[a],H),甚至'分([a | _],[b | _],_)'很好地终止。 – false

0

另一个答案, 采用回溯了很多,是不是很高性能的,但。 appendlength被假定为预定义:

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). 

哦,不好意思,刚才已经看到,这是种由菲利普·怀特豪斯回答的改述的。

0

这就是我做到的。几乎没有内置插件:

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) 
    .