除了@GuyCoder 的回答之外,我还要指出,在修改列表的所有元素时,值得考虑使用 library(apply) 中的 maplist 谓词之一。可以用谓词来描述三个数之间的关系...
:- use_module(library(apply)). % for maplist/4
num_num_sum(X,Y,S) :-
S is X+Y.
...然后使用 maplist/4 将其应用于整个列表:
fn(X,Y,Z) :-
maplist(num_num_sum,X,Y,Z).
如果前两个列表完全实例化,则此谓词会产生所需的结果:
?- fn([1,2,3],[4,5,6],X).
X = [5,7,9]
但是,由于使用 is/2,如果前两个列表包含变量,则会出现实例化错误:
?- fn([1,A,3],[4,5,6],[5,7,9]).
ERROR at clause 1 of user:num_num_sum/3 !!
INSTANTIATION ERROR- X is _+B: expected bound value
?- fn([1,2,3],[4,5,A],[5,7,9]).
ERROR at clause 1 of user:num_num_sum/3 !!
INSTANTIATION ERROR- X is A+B: expected bound value
如果您只想对整数列表使用谓词,可以使用CLP(FD) 使其更加通用:
:- use_module(library(apply)).
:- use_module(library(clpfd)). % <- use CLP(FD)
int_int_sum(X,Y,S) :-
S #= X+Y. % use CLP(FD) constraint #=/2 instead of is/2
fnCLP(X,Y,Z) :-
maplist(int_int_sum,X,Y,Z).
有了这个定义,以前有问题的查询也可以工作:
?- fnCLP([1,A,3],[4,5,6],[5,7,9]).
A = 2
?- fnCLP([1,2,3],[4,5,A],[5,7,9]).
A = 6
即使是最一般的查询也会在此版本中产生结果:
?- fnCLP(X,Y,Z).
X = Y = Z = [] ? ;
X = [_A],
Y = [_B],
Z = [_C],
_A+_B#=_C ? ;
X = [_A,_B],
Y = [_C,_D],
Z = [_E,_F],
_A+_C#=_E,
_B+_D#=_F ? ;
.
.
.
由于上述答案中的数字不是唯一确定的,因此您得到的是剩余目标而不是实际数字。为了获得答案中的实际数字,您必须限制两个列表的范围并随后标记它们(有关详细信息,请参阅documentation),例如要生成包含第一个列表中的数字 3、4、5 和第二个列表中的数字 6、7、8 的列表,您可以查询:
label the lists
restrict the domain | |
v v v v
?- fnCLP(X,Y,Z), X ins 3..5, Y ins 6..8, label(X), label(Y).
X = Y = Z = [] ? ;
X = [3],
Y = [6],
Z = [9] ? ;
X = [3],
Y = [7],
Z = [10] ? ;
.
.
.
X = [3,4],
Y = [6,7],
Z = [9,11] ? ;
X = [3,4],
Y = [6,8],
Z = [9,12] ? ;
.
.
.
另外说明:还有布尔 (CLP(B))、有理数和实数 (CLP(Q,R)) 的 clp 库,您可能会觉得有趣。