我正在尝试在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).
请帮忙......我很蠢。谢谢!
答案 0 :(得分:2)
您的代码存在一些问题:
您使用自己定义的谓词isNum
,但只有6
似乎是一个数字。 0
不是数字?所以纠正这个:
isNum(0).
isNum(6).
或使用swi-prolog的内置谓词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/2
到findNumber/3
转换所做的事情。
有一种特殊情况,Prolog会怀疑是否存在子列表(第二个子句),它将使用列表findNumber/3
的头部调用findNumber(H,TA,TL)
并生成列表{{ 1}}将尾部TA
打开。新尾TL
稍后将填充调用TL
(因此我们将原始尾findNumber(H,TL,TT)
置于真实背后,但需要中间尾TT
)
演示(TL
):
swipl