我在这里找出一个简单的Prolog问题时遇到了一些麻烦。 我需要在原子列表的元素上执行某种操作(由我自己定义)。但是,如果列表中的元素对于指定的谓词P(x)返回true,我应该只执行这样的操作。
所以基本上,如果我有规则:
mutate_if(isOdd, addOne, [1,2,3,4,5], L2).
我应该得到以下输出:
L2 = [2,2,4,4,6]
到目前为止,我已经提出了这个代码
mutate_if(P, OP, L1, L2):-
findall(Y, ((member(X,L1),
Oper=.. [P,X],
call(Oper)) -> (Mutate=.. [OP, X, Y], call(Mutate)); X=Y),
L2).
在我看来,这应该运作良好,但是当我在Prolog-SWI上运行时,我得到以下内容:
?- mutate_if(isOdd, addOne, [1,2,3,4,5], L2).<
L2=[2].
其中isOdd
和addOne
都是简单的规则,它们检查输入变量是否为奇数,并分别在输入变量中加1。
我无法弄清楚当findall
谓词在技术上应该找到第一个列表的所有成员时,为什么Prolog只找到列表中的一个元素。
这是我自己的逻辑错误吗?
答案 0 :(得分:2)
一些建议......
您不需要=../2
。 call(P, X)
会使用参数P
调用仿函数X
,而call(OP, X, Y)
将使用参数OP
和X
调用仿函数Y
。
如果您正确设置了条件,可以在此处使用findall
。它将收集导致给定表达式成功的值(产生true
)。由于您希望将映射列表中的每个元素添加到结果中,因此我会将maplist/3
与谓词类似,mutate_one_if(P, OP, X, Y)
将单个X
变为{ {1}}或单独留下(Y
),具体取决于条件(按照您的要求)。
X = Y
mutate_one_if(P, OP, X, Y) :-
( call(P, X)
-> call(OP, X, Y)
; X = Y
).
mutate_if(P, OP, L1, L2) :-
maplist(mutate_one_if(P, OP), L1, L2).
会针对maplist/3
和mutate_one_if(P, OP)
中的每个对应元素致电L1
。如您所见,L2
非常灵活,因为如果您想致电call
,可以将其称为mutate_one_if(P, OP, X, Y)
或call(mutate_one_if(P, OP), X, Y)
。 Prolog的call(mutate_one_if(P, OP, X, Y))
将适当地收集论据。
所以,使用这些:
call
收率:
isOdd(X) :- X /\ 1 =:= 1.
addOne(X, Y) := Y is X + 1.
答案 1 :(得分:2)
我认为你没有正确确定'if / then / else'操作数。 有了这个定义
mutate_if(P, OP, L1, L2):-
findall(Y, (
member(X,L1),
Oper=.. [P,X],
( call(Oper) -> Mutate=.. [OP, X, Y], call(Mutate); X=Y )
), L2).
我得到了
?- mutate_if(isOdd, addOne, [1,2,3,4,5], L).
L = [2, 2, 4, 4, 6].
(请注意@lurker建议非常有价值)