请让我们退后一步,考虑一些比如何使用一个或两个特定谓词(例如!/0
or )更普遍的问题not/1
。
首先,让我们修复一些语法问题,并让您的原始代码如下所示:
选择(0,_,[]):-!。
选择(N,[H|T],[H|R]):- M 是 N-1,选择(M,T,R)。
选择(N,[_|T],R):-选择(N,T,R)。
全选(N,L,Res):-
全选(N,L,[],Res)。
全选(N,L,Seen,Res):-
选择(N,L,R),
不是(成员(R,Seen)),
!,
全选(N,L,[R|Seen],Res)。
全选(_,_,Res,Res)。
从这里开始,我应用了以下两个小改动:
- 而不是
not/1
, 我使用,(\+)/1
因为(\+)/1
是 ISO 但不是.not/1
- 而不是
(is)/2
,我使用 CLP(FD) 约束(#=)/2
来宣传更新的语言结构,并明确说明在这种情况下我们仅对整数进行推理,而不是例如浮点数或其他类型的数字。将此视为保证额外的类型安全性。
我们获得了这两个小变化:
选择(0,_,[]):-!。
选择(N,[H|T],[H|R]):- M #= N-1,选择(M,T,R)。
选择(N,[_|T],R):-选择(N,T,R)。
全选(N,L,Res):-
全选(N,L,[],Res)。
全选(N,L,Seen,Res):-
选择(N,L,R),
\+ 成员(R,Seen),
!,
全选(N,L,[R|Seen],Res)。
全选(_,_,Res,Res)。
现在让我们开始吧!我渴望通过询问来尝试主要谓词:到底有哪些解决方案?
为了找出答案,我发布了所谓的最通用查询,其中所有参数都是新变量:
?- 全选(X, Y, Z)。
X = 0,
Z = [[]]。
什么?这个谓词只有一个解,对吧?正确的?
可能不是。
所以,我想得到更多关于这些基本问题的答案。为了获得它们,我进行了以下附加更改:
- 我删除
!/0
.
- 我曾经
dif/2
说过两个术语是不同的。
- 我稍微重新排列了条款。
- 我为那些仅在大于 0
N #> 0
时才适用的子句添加了约束。N
所以,我们有:
选择(0,_,[])。
选择(N,[H|T],[H|R]):- N #> 0,M #= N-1,选择(M,T,R)。
选择(N,[_|T],R):- N#> 0,选择(N,T,R)。
全选(N,L,Res):-
全选(N,L,[],Res)。
全选(_,_,Res,Res)。
全选(N,L,Seen,Res):-
选择(N,L,R),
maplist(dif(R), Seen),
全选(N,L,[R|Seen],Res)。
现在我们有例如:
?- 全选(X, Y, Z)。
Z = [];
X = 0,
Z = [[]] ;
X = 1,
Y = [_1966|_1968],
Z = [[_1966]] ;
X = 1,
Y = [_3214, _3220|_3222],
Z = [[_3220],[_3214]],
差异(_3220,_3214);
X = 1,
Y = [_3560, _3566, _3572|_3574],
Z = [[_3572],[_3566],[_3560]],
差异(_3572,_3560),
差异(_3572,_3566),
差异(_3566,_3560)。
X = 0,
Z = [[]]。
我把它作为一个练习来确定这个程序现在是否过于笼统、过于具体或两者兼而有之,并添加或删除必要的约束以仅获得所需的答案。
我想说明的要点是,坚持纯谓词可以帮助您获得更通用的程序。使用!/0
and(\+)/1
并没有帮助。为了避免在特定情况下回溯,同时保持谓词的通用性,例如使用新的谓词 if_/3
。