2017-10-09 94 views
3

我正在寫prolog代碼,發現一定數量;如果數字介於0到9之間並且不在給定列表中,則數字是正確的數字。要做到這一點,我寫了一個謂語number/3有可能的數字作爲第一個參數,其中Rightnumber不能出現在列表和神祕RightNumber作爲第三個參數:如何改進查找列表中特定數字的代碼?

number([XH|XT], [H|T], RightNumber):- 
    member(XH, [H|T]), !, 
    number(XT, [H|T], RightNumber). 
number([XH|_], [H|T], XH):- 
    \+ member(XH, [H|T]). 

所以這段代碼基本上是說,如果可能的數字列表的頭已經是第二個列表的成員,切割頭部並繼續與尾部遞歸。 如果元素不在第二個列表中,則第二個子句觸發並告訴序言該數字是RightNumber。沒關係,它只給出了可能的第一個數字,這就是我想要使用的數字。

這段代碼在理論上有效,但我想知道是否有更好的方法來寫下它?我在我的代碼中稍後在另一個謂詞中使用了這個謂詞,它不作爲其中的一部分工作。我認爲它只是讀取第一個條款,而不是第二個條款,因此失敗。

有沒有人有一個想法,可能會改善我的代碼?

查詢示例:

?- number([0,1,2,3,4,5,6,7,8,9], [1,2], X). 
     X = 3 
?- number([0,1,2,3,4,5,6,7,8,9], [1,2,3,4,5,6,7,8,0], X). 
     X = 9 

回答

5

首先,代碼不工作。試想一下:

 
?- number(Xs, Ys, N). 
nontermination 

這顯然是:對於這個所謂的最一般的查詢,我們希望得到回答,但序言並沒有給我們這個程序的任何答案!

所以,我首先建議你消除你的程序中的所有雜質,並專注於你想要什麼乾淨聲明描述。

我給你一個開始:

 
good_number(N, Ls) :- 
     N in 0..9, 
     maplist(#\=(N), Ls). 

這說明關係是真實的如果N是0和之間  9,N是任意整數不同的  Ls。有關CLP(FD)約束的更多信息,請參見

重要的是,這項工作在所有方向。例如:

 
?- good_number(4, [1,2,3]). 
true. 

?- good_number(11, [1,2,3]). 
false. 

?- good_number(N, [1,2,3]). 
N in 0\/4..9. 

而且在最一般的情況:

 
?- good_number(N, Ls). 
Ls = [], 
N in 0..9 ; 
Ls = [_2540], 
N in 0..9, 
N#\=_2540 ; 
Ls = [_2750, _2756], 
N in 0..9, 
N#\=_2756, 
N#\=_2750 . 

此,只有兩行代碼,我們實現了一個非常一般關係。

另請參閱瞭解更多信息。

0

首先,您的謂詞不起作用,也不會檢查所有必需的約束(例如0到9之間)。

幾件事情:

  • 您打開第二個列表[H|T],但你重新 -pack它,當你調用member(XH, [H|T]);相反,您可以使用列表L(但這會稍微改變謂詞的語義,但對描述更準確);
  • 你檢查兩次member/2船;
  • 您不檢查值是否爲09(和整數無論如何)之間的數字。

一種更好的方法是構造一個簡單子句:

number(Ns, L, Number) :- 
    member(Number, Ns), 
    integer(Number), 
    0 =< Number, 
    Number =< 9, 
    \+ member(Number, L). 

剩下是Number可以是可變的問題。在這種情況下,integer(Number)將會失敗。然而在邏輯上,我們會期望Prolog將它與一個數字統一起來。我們可以通過使用between/3謂詞實現這一點:

number(Ns, L, Number) :- 
    member(Number, Ns), 
    between(0, 9, Number), 
    \+ member(Number, L). 

我們還可以使用Ç onstraint 大號邏輯P在AGC在˚F inite d omains庫,並使用in/2謂詞:

:- use_module(library(clpfd)). 

number(Ns, L, Number) :- 
    member(Number, Ns), 
    Number in 0..9, 
    \+ member(Number, L). 

還有其他的事情可能會出錯。例如,我們使用\+ member(Number, L).來檢查非會員資格,但是如果L沒有接地,這將會失敗,而不是建議沒有任何元素等於Number的列表,我們可以使用元斷言maplist來構造列表,然後調用對每個元素的謂詞。我們要調用每個元素的謂詞是該元素不等於Number,所以我們可以使用:

:- use_module(library(clpfd)). 

number(Ns, L, Number) :- 
    member(Number, Ns), 
    Number in 0..9, 
    maplist(#\=(Number), L). 
相關問題