列出Prolog列表中的数字列表

时间:2015-11-27 17:56:06

标签: list prolog

我正在尝试在Prolog中为它找到的每个数字构建一个列表。例如,findNumber([g,o,o,d,j,0,6],[0,6]),但我无法使用给定代码构建列表:

isNum(6).
isNum(6).

findNumber([],[]).
findNumber([V|T],[-|TAfter]) :-
  isNum(V),
  findNumber(T,TAfter).
findNumber([H|T],[H|TAfter]) :-
  not(isNum(H)),
  findNumber(T,TAfter).

请帮忙......我很蠢。谢谢!

1 个答案:

答案 0 :(得分:2)

您的代码存在一些问题:

您使用自己定义的谓词isNum,但只有6似乎是一个数字。 0不是数字?所以纠正这个:

isNum(0).
isNum(6).

或使用的内置谓词number/1。 (注意使用number/1稍微修改了语义,因为number/1没有实例化给定变量;只要你只在一个方向使用谓词 - 列表到子列表 - 并且不使用未实例化的变量,那么&#但是很好)。

其次是谓词本身。首先,你以某种方式交换了案例:这里它会将H添加到第三个子句中的结果列表中(其中H不是数字)。此外,在第二个子句中,您将短划线(-)添加到列表中(这似乎不是所需的行为)。因此,更好的谓词可能是:

findNumber([],[]).
findNumber([H|T],[H|TAfter]) :-
  number(H),
  findNumber(T,TAfter).
findNumber([H|T],TAfter):-
  not(number(H)),
  findNumber(T,TAfter).

或者你可以通过使用剪切(!)使谓词更紧凑(并且更快):

findNumber([],[]).
findNumber([H|T],[H|TAfter]) :-
  number(H),
  !,
  findNumber(T,TAfter).
findNumber([_|T],TAfter):-
  findNumber(T,TAfter).

演示(swipl):

?- findNumber([g,o,o,d,j,0,6],X).
X = [0, 6].

?- findNumber([g,o,0,o,d,j,6],X).
X = [0, 6].

递归列表结构

如果您想以递归方式执行此操作,可以通过将谓词扩展为三个参数版本findNumber/3来完成此操作。首先,我们在findNumber/2上使用两个参数findNumber/3映射版本:

findNumber(A,B) :-
    findNumber(A,B,[]).

(应删除先前定义的谓词)。

接下来我们定义以下子句:

findNumber([],TT,TT).
findNumber([H|T],[H|TA],TT) :-
  number(H),
  !,
  findNumber(T,TA,TT).
findNumber([H|T],TA,TT):-
  findNumber(H,TA,TL),
  !,
  findNumber(T,TL,TT).
findNumber([_|T],TA,TT) :-
    findNumber(T,TA,TT).

这适用于一种称为差异列表的技术,它将具有相当的内存和CPU效率。此外,调用堆栈只会增加给定列表的级别数。

第三个参数指定应将哪个值放在列表的尾部。显然,基本情况是列表应以[]结尾(这是我们对findNumber/2findNumber/3转换所做的事情。

有一种特殊情况,Prolog会怀疑是否存在子列表(第二个子句),它将使用列表findNumber/3的头部调用findNumber(H,TA,TL)并生成列表{{ 1}}将尾部TA打开。新尾TL稍后将填充调用TL(因此我们将原始尾findNumber(H,TL,TT)置于真实背后,但需要中间尾TT

演示(TL

swipl