2017-06-10 104 views
2

我需要做的是編寫一個謂詞,它包含一個數字列表並返回一個由兩個元素組成的列表,第一個是偶數和第二個是奇數的總和。Prolog中列表的偶數和奇數的總和

例如:

?- sum([5,4,9,8,1,7], L). 
L = [12, 22]. 

到目前爲止,我已經寫了:

iseven(N) :- 
    0 is mod(N,2). 
+1

您是否嘗試過除了你'ISEVEN/1'謂語什麼? – lurker

回答

3

既然你已經定義iseven/2你可以使用它像:

sum([],[0,0]). 
sum([H|T],[N1,N2]):- 
      sum(T,[N3,N4]), 
      (iseven(H) 

       -> N1 is N3+H, N2 is N4 
       ; N2 is N4+H, N1 is N3 

      ). 

例子:

使用

非的if-then-else的版本不同的條款:

sum([],[0,0]). 
sum([H|T],[N1,N2]):- sum(T,[N3,N2]), iseven(H), N1 is N3+H. 
sum([H|T],[N1,N2]):- sum(T,[N1,N3]), \+ iseven(H), N2 is N3+H. 
+0

這種方法完美地工作,但我知道這使用了我們沒有教過的if-then-else方法(這是我的一門課的練習)。 – sarotnem

+1

@sarotnem因爲這是一項家庭作業,您應該嘗試理解原始答案中確立的原則並提出解決方案。這不是一個人們在這裏爲你做所有的家庭作業的網站。原來的解決方案使用你可以適應的原則來提出一個非if-else-else的方法。 – lurker

+1

@lurker我試圖解決這個問題約2小時,我總是以錯誤結束。發生這種情況是因爲我試圖實現經典的if-then-else解決方案,當然沒有成功。信不信由你,看到這個答案後,我明白了原理,並將其應用於我所做的類似功課!所以我想對我來說這種方式很有用:) – sarotnem

1

您可以使用functionnal方式:

one_sum(X, [SE,SO], [SE1, SO1]) :- 
    ( X mod 2 =:= 0 -> 
     SE1 is SE+X, SO1 = SO 
    ; SE1 = SE, SO1 is SO+X). 

sum(L, S) :- 
    foldl(one_sum, L, [0,0], S). 
3

你也可以使用蓄電池和if_/3寫這個斷言。此外,你還可以將的iseven/1的單一目標到謂語:

list_sums(L,S) :- 
    list_sums_(L,S,0-0). 

list_sums_([],[E,O],E-O). 
list_sums_([X|Xs],S,E0-O0) :- 
    M is X mod 2, 
    if_(M=0,(E1 is E0+X, O1 is O0),(E1 is E0, O1 is O0+X)), 
    list_sums_(Xs,S,E1-O1). 

注意蓄電池是如何寫成一對(E-O)。如果您可以自由選擇這兩個元素的表示形式,則這一對符號可以替代具有兩個元素的列表。你的榜樣查詢產生期望的結果:

?- list_sums([5,4,9,8,1,7],L). 
L = [12, 22]. 

和示例從註釋終止相當快:

?- length(L,100),maplist(=(1),L),time(list_sums(L,[A,B])). 
% 703 inferences, 0.000 CPU in 0.000 seconds (100% CPU, 3426895 Lips) 
L = [1, 1, 1, 1, 1, 1, 1, 1, 1|...], 
A = 0, 
B = 100. 

然而,由於使用的is/2,這是隻在一個方向努力。如果你想在另一個方向使用謂詞,你可以選擇使用CLP(FD)。在這種情況下,包括在源文件中的行

:- use_module(library(clpfd)). 

#=/2取代的is/2所有出現在list_sums_/3

list_sums_([],[E,O],E-O). 
list_sums_([X|Xs],S,E0-O0) :- 
    M #= X mod 2, 
    if_(M=0,(E1 #= E0+X, O1 #= O0),(E1 #= E0, O1 #= O0+X)), 
    list_sums_(Xs,S,E1-O1). 

你的榜樣查詢仍得到相同的結果,並從意見的例子終止於可接受的時間:

?- length(L,100),maplist(=(1),L),time(list_sums(L,[A,B])). 
% 18,928 inferences, 0.004 CPU in 0.004 seconds (99% CPU, 4888152 Lips) 
L = [1, 1, 1, 1, 1, 1, 1, 1, 1|...], 
A = 0, 
B = 100. 

但謂詞w現在在兩個方向都可以使用。在某些情況下的Prolog可以找到具體的答案事不宜遲:

?- list_sums([A,B],[2,1]). 
A = 2, 
B = 1 ; 
A = 1, 
B = 2 ; 
false. 

在其他情況下你會得到剩餘的目標作爲一個答案:

?- L=[A,B,C,D,E,F], list_sums(L,[12,22]). 
L = [A, B, C, D, E, F], 
A+B#=_G3306, 
A mod 2#=0, 
B mod 2#=0, 
_G3306+C#=_G3342, 
C mod 2#=0, 
_G3342+D#=12, 
D mod 2#=0, 
E+F#=22, 
E mod 2#=_G3402, 
F mod 2#=_G3414, 
_G3414 in 0..1, 
dif(_G3414, 0), 
_G3402 in 0..1, 
dif(_G3402, 0) ; 
... 

在這種情況下,你可以限制列表的一些元素間隔並使用label/1來獲得具體的數字作爲解決方案。例如,你可以要求從零六個數字解決方案,以七序言會給你所有的300個解決方案:

?- length(L,6), L ins 0..7, list_sums(L,[12,22]), label(L). 
L = [6, 6, 1, 7, 7, 7] ; 
L = [6, 6, 3, 5, 7, 7] ; 
...