2017-10-09 92 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). 
相关问题