序言 - 递归列表建设(Prolog - recursive list building)

2019-09-16 09:49发布

一个程序我写我需要做一个列表的列表,以表示对2张中给出数的积和数字。

现在,我有我可以指定我想多少次列表添加到列表中,将与全功能以后可以扩展的功能。

下面是我有:

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]]

Answer 1:

所以,有很多事情在这里说。 首先,在大多数声明性语言,一个变量不能真正改变值。

这是什么意思的是, X = 1.将统一1X如你所期望的,但如果你加X = 2.后,在您的查询( X = 1, X = 2. ),Prolog的会说false 。 背后的原因是,你不能统一12X已真正成为1 ,因此X不能统一到2

虽然,从Haskell中,ocaml的而不同,可以部分地结合的变量,如X = h(Y). 。 然后,您就可以进一步统一其X = h(a(Z)). ,而你不能在语言早期mentionned(其中一个变量实际上只是一个别名的值)。

为什么他告诉我说你不知道? 好了,这里是你的主要问题。 你先绑定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),

没有任何信息损失,因为你不使用AB一次。

现在,让我们忘掉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).

现在,如果你测试,你可能此话的程序循环,就像你当你打的; 键。 这是因为序言认为第二条款可以适用于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谓词,因为我的有关变量的散漫应该已经告诉你很多不好的事了。



文章来源: Prolog - recursive list building
标签: prolog