请让我们退后一步,考虑一些比如何使用诸如!/0 或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)。
由此开始,我应用以下两个小改动:
- 我使用
(\+)/1 而不是not/1,因为(\+)/1 是ISO,但not/1 是,嗯,不是。
- 我使用 CLP(FD) 约束
(#=)/2 而不是 (is)/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 表示两个术语不同。
- 我稍微重新排列了条款。
- 我为那些仅在
N 大于 0 时适用的子句添加了约束 N #> 0。
所以,我们有:
选择(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 = [[]]。
我把它作为一个练习来确定这个程序现在是否过于笼统、过于具体或两者兼而有之,并添加或删除必要的 约束 以获取 only 想要的答案。
我想展示的主要观点是,坚持纯谓词可以帮助您获得更通用的程序。使用 !/0 和 (\+)/1 对此无济于事。为了避免在特定情况下回溯,同时保持谓词的通用性,例如使用新的谓词if_/3。