如何改进查找列表中特定数字的代码?

时间:2017-10-09 17:10:12

标签: prolog

我正在写一个找到一定数字的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]).

所以这段代码基本上说如果可能的数字列表的头部已经是第二个列表的成员,则剪掉头部并继续用尾部递归。 如果元素不在第二个列表中,则第二个子句触发并告诉prolog该数字是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

2 个答案:

答案 0 :(得分:5)

首先,代码工作。考虑:

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

这显然糟糕:对于这个所谓的最常见的查询,我们希望获得答案,但Prolog不会给我们这个程序的任何答案!

所以,我首先建议你从你的程序中消除所有杂质,并专注于你想要的干净的声明描述。

我给你一个开始:

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

这表明关系为真如果 GenericValue介于0和9之间, N与{{}中的任何整数都不同1}}。有关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 .

这只有两行代码,我们实现了非常通用关系。

另请参阅了解详情。

答案 1 :(得分:0)

首先,你的谓词不起作用,也不检查所有必需的约束(例如0到9之间)。

有几件事:

  • 您解压缩了第二个列表[H|T],但是当您致电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).

我们还可以使用 C onstraint L ogic P 编程 F inite D < / strong> omains library并使用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).