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

Prolog 如何改进在列表中查找特定数字的代码?,prolog,clpfd,logical-purity,Prolog,Clpfd,Logical Purity,我正在编写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],

我正在编写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

首先,代码不起作用。考虑:

?- number(Xs, Ys, N). nontermination 在最普遍的情况下:

?- 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 . ?-良好的_数(N,Ls)。 Ls=[], N在0..9; Ls=[[u 2540], N在0..9中, N\=\u 2540; Ls=[[u 2750,[u 2756], N在0..9中, N\=\u 2756, N\=\u 2750。 这只需要两行代码,我们就实现了一个非常一般的关系


有关更多信息,请参见。

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

有几件事:

  • 您解包了第二个列表
    [H|T]
    ,但在调用
    成员(XH[H|T])
    时重新打包了它;相反,您可以使用list
    L
    (不过这稍微改变了谓词的语义,但对描述更为准确)
  • 您检查两次
    member/2
    ship
  • 您不检查该值是否是介于
    0
    9
    之间的数字(而且还是整数)
更好的方法是构造一个简单的子句:

number(Ns, L, Number) :-
    member(Number, Ns),
    integer(Number),
    0 =< Number,
    Number =< 9,
    \+ member(Number, L).
我们还可以使用ConstraintLogicpFiniteD域库上编程,并使用
in/2
谓词:

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

number(Ns, L, Number) :-
    member(Number, Ns),
    Number in 0..9,
    \+ member(Number, L).
还有其他一些事情可能出错。例如,我们用
\+member(Number,L)检查非成员身份。
但是如果
L
不固定,这将失败,我们可以使用元谓词
maplist
构造列表,然后对每个元素调用谓词,而不是建议元素都不等于
Number
的列表。我们希望调用每个元素的谓词是该元素不等于
Number
,因此我们可以使用:

:- use_module(library(clpfd)).

number(Ns, L, Number) :-
    member(Number, Ns),
    Number in 0..9,
    maplist(#\=(Number), L).
:- use_module(library(clpfd)).

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

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