我想用findall / 3将List中的元素相乘。具体来说,我有两个函数double(X,Y),它们将X加倍,而square(X,Y)返回X的平方值。我的问题是,该操作仅适用于列表的第一个元素。
double(X,Y) :- Y is X*2.
square(X,Y) :- Y is X*X.
map_f(Operation,[H|List],[R|Results]) :-
Predicate=..[Operation,H,R],
call(Predicate),
findall(X,( member(X,List) ), Results).
例如,如果我输入map_f(double,[3,1,2,6,3,1,6],L).
,
我希望输出:L = [6,2,4,12,6,2,12]
,
但它显示:
?- map_f(double, [3, 1, 2, 6, 3, 1, 6], List).
List = [6, 1, 2, 6, 3, 1, 6]
Yes (0.00s cpu)
任何帮助将不胜感激。
答案 0 :(得分:0)
如果要使用findall/3
,则必须这样写:
?- Xs = [3,1,2,6,3,1,6], findall(Y, ( member(X, Xs), double(X, Y) ), Ys).
Xs = [3, 1, 2, 6, 3, 1, 6],
Ys = [6, 2, 4, 12, 6, 2, 12].
如果您真的想将谓词作为参数传递并使用=..
,则逻辑仍然是相同的,您只需要重新编写您的定义即可执行正确的操作:>
map_f(Pred_name, L1, L2) :-
Goal =.. [Pred_name, X, Y],
findall(Y, ( member(X, L1), Goal ), L2).
然后:
?- map_f(double, [3,1,2,6,3,1,6], R).
R = [6, 2, 4, 12, 6, 2, 12].
?- map_f(square, [3,1,2,6,3,1,6], R).
R = [9, 1, 4, 36, 9, 1, 36].
但是,而不是:
Goal =.. [Pred_name, Arg1, Arg2], Goal
使用call/N+1
更容易:
call(Pred_name, Arg1, Arg2)
因此您的定义将变为:
map_f(Pred_name, L1, L2) :-
findall(Y, ( member(X, L1), call(Pred_name, X, Y) ), L2).
但是,实际上,如果只有列表,那么所有这些都是完全不必要的。您可以像这样使用maplist/N+1
:
?- maplist(double, [3,1,2,6,3,1,6], R).
R = [6, 2, 4, 12, 6, 2, 12].
...遍历列表,而不是回溯它们。例如,您可以在此处查看maplist
的实现:
如果谓词是真实关系(因此,如果双向都起作用),则也可以同时使用maplist
。 findall
无法做到!这是一个愚蠢的例子:
?- maplist(succ, [1,2,3], R).
R = [2, 3, 4].
?- maplist(succ, R, [1,2,3]).
R = [0, 1, 2].
?- map_f(succ, [1,2,3], R).
R = [2, 3, 4].
?- map_f(succ, R, [1,2,3]).
ERROR: Arguments are not sufficiently instantiated