对于我正在编写的程序,我需要列出一个列表,一对数字代表一个产品,两个给定数字的总和。
现在我有一个函数,我可以指定我想在列表中添加一个列表的次数,稍后将使用完整功能进行扩展。
这就是我所拥有的:
s1(0, X).
s1(Q, X) :-
N is Q - 1,
multiply(2, 3, Y),
A = Y ,
add(2, 3, Z),
B = Z,
addToEnd([A], [B], X),
s1(N,X).
multiply(A, B, C):-
C is A * B.
add(A, B, C) :-
C is A + B.
addToEnd([], L, L).
addToEnd([H|T], L2, [H|L3]) :-
addToEnd(T, L2, L3).
但是,例如,当我运行s1(2,X)
时,我会返回[6,5]
,然后没有别的,只是挂起。当我运行s1(0,X)
时,我会true
,然后false
,当我点击;
时
任何人都可以帮我吗?我看不出我做错了什么,我觉得它应该有效!
澄清我认为这应该如何运作:
我打电话给s1(2,X).
N = 1
,[6,5]
已添加到X([[6,5]])
的列表中
s1(1,X).
N=0
,[6,5]
已添加到X ([[6,5],[6,5]])
的列表中
s1(0,X).
X = [[6,5],[6,5]]
答案 0 :(得分:5)
所以,这里有很多话要说。首先,与大多数声明性语言一样,变量不能真正改变价值。
这意味着X = 1.
会将1
统一为X
,但是如果您在查询中添加X = 2.
(X = 1, X = 2.
}),Prolog会说false
。这背后的原因是您无法将1
与2
统一,X
真正成为1
,因此X
无法统一为2
}。
虽然,与Haskell,Ocaml等不同,您可以部分绑定变量,如X = h(Y).
中所示。然后,您将能够进一步统一它X = h(a(Z)).
,而您不能使用之前提到的语言(变量实际上只是值的别名)。
为什么他告诉我你想知道的一切?嗯,这是你的主要问题。您首先将X
绑定到[6, 5]
,然后期望进一步将其绑定到其他一些东西。一旦变量被接地(即内部不包含任何自由变量),您就不能再次更改其值。
所以在这里你的递归不会做任何事情,但最终证明X
是假的。但是,由于您最终每次都使用相同的参数调用addToEnd/3
([6]
,[5]
和[6, 5]
),所以不会这样做。
话虽如此,让我们来看看我们如何改进您的代码。
首先,一句话:
multiply(2, 3, Y),
A = Y ,
add(2, 3, Z),
B = Z,
addToEnd([A], [B], X),
可以写
multiply(2, 3, Y),
add(2, 3, Z),
addToEnd([Y], [Z], X),
没有任何信息丢失,因为您再次不使用A
和B
。
现在,让我们暂时忘记addToEnd/3
并考虑一下你想要的东西。
如果您输入s1(0, Q)
,您真的希望Q
免费吗?因为这就是你现在所说的。在这种情况下,将Q
绑定到[]
会更有意义。此外,这将是一个很好的递归基础案例,你很快就会看到。
s1(0, []).
是说
的捷径s1(0, Q) :- Q = [].
因为Prolog在子句头(:-
之前的部分)中进行了统一。
然后,我会欺骗一点,但这只是为了保持清醒。你可以说当从s1(4, Q)
转到s1(5, Q)
时,你希望Q再拿一些微积分值。
在这里,我们可以说明如下:
s1(N, [SomeCalculus|Q]) :-
PreviousN is N - 1,
s1(PreviousN, Q).
现在,我们只需要为SomeCalculus
提供一个值:
s1(N, [SomeCalculus|Q]) :-
PreviousN is N - 1,
X is 2 * 3,
Y is 2 + 3,
SomeCalculus = [X, Y],
s1(PreviousN, Q).
或者,如果你正确地遵循,我们可以直接写:
s1(N, [[X, Y]|Q]) :-
PreviousN is N - 1,
X is 2 * 3,
Y is 2 + 3,
s1(PreviousN, Q).
所以完整的程序将是:
s1(0, []).
s1(N, [[X, Y]|Q]) :-
PreviousN is N - 1,
X is 2 * 3,
Y is 2 + 3,
s1(PreviousN, Q).
现在,如果你测试它,你可能会注意到当你点击;
键时程序就像你的那样循环。那是因为Prolog认为第二个条款适用于0
太
让我们再次编辑程序:
s1(0, []).
s1(N, [[X, Y]|Q]) :-
N > 0,
PreviousN is N - 1,
X is 2 * 3,
Y is 2 + 3,
s1(PreviousN, Q).
现在一切都很好。
我希望这能帮助您更好地理解如何通过递归构建正确的谓词。我没有花太多时间来纠正你的addToEnd/3
谓词,因为我对变量的讨论应该已经告诉了你很多关于它的错误。