简体   繁体   English

[--I,++ J]的Prolog递归构建列表,而J> 0

[英]Prolog Recursive Build List of [--I, ++J], while J>0

I'm trying to put together a Prolog program that will take in a number and an output list, and essentially make a list of the form [I, J], where I+J = N. Here's the code I have, with the output I'm getting: 我正在尝试将一个Prolog程序放在一起,该程序将接收一个数字和一个输出列表,并从本质上列出[I,J]形式的列表,其中I + J =N。这是我的代码,我得到的输出:

loop(I, J, [[X,Y]|Lout]):-
  I > 0,
  I1 is I-1,
  J1 is J+1,
  X is I1,
  Y is J1,
  loop(I1, J1, Lout).
loop(I, J, [[I,J]]).

listFromLoop(N, W):-
  loop(N,0,W).

Output: 输出:

?- listFromLoop(4,W).
W = [[3, 1], [2, 2], [1, 3], [0, 4], [0, 4]] ;
W = [[3, 1], [2, 2], [1, 3], [1, 3]] ;
W = [[3, 1], [2, 2], [2, 2]] ;
W = [[3, 1], [3, 1]] ;
W = [[4, 0]].

I'm getting two extra elements at the end ([0,4], [0,4]) that I don't need, as well as having to step through it, rather than it all being displayed as a single list. 我在末尾得到了两个我不需要的额外元素([0,4],[0,4]),并且不得不逐步执行,而不是全部显示为一个列表。

Here is what it is supposed to look like: 这是应该的样子:

?- listFromLoop(4,W).
W = [[3, 1], [2, 2], [1, 3]].

I'm close, but I think my main problem is that I'm trying to code it like I would a C++ or Java while-loop. 我已经接近了,但是我认为我的主要问题是我试图像对C ++或Java while循环那样进行编码。 However, that doesn't seem to be the proper way to go about it in Prolog. 但是,这似乎不是在Prolog中解决该问题的正确方法。

Any help would be much appreciated! 任何帮助将非常感激!

EDIT 编辑

I figured it out! 我想到了! After a little bit more reading, it seemed I was missing my base case for the recursive version. 多一点阅读后,似乎我缺少递归版本的基本情况。 Here is what I ended up with that fixed it. 这就是我最终解决的问题。 Although, I'm not certain this is necessarily the correct/most efficient way to do this in Prolog. 尽管我不确定这是否一定是Prolog中正确/最有效的方法。

loop(1,_,[]):- !.
loop(I, J, [[X,Y]|Lout]):-
  I > 0,
  I1 is I-1,
  J1 is J+1,
  X is I1,
  Y is J1,
loop(I1, J1, Lout).

listFromLoop(N, W):-
  loop(N,0,W).

Your code is fine, but I would do this kind of thing to clean it up a bit: 您的代码很好,但是我会做一些事情来清理它:

build(1, _, []).
build(I, J, [[X, Y]|Zs]) :-
    I > 1,
    X is I - 1,
    Y is J + 1,
    build(X, Y, Zs).

build(N, W) :- build(N, 0, W).

You're not really using a loop - it's recursion that builds the list. 您并不是真正在使用循环-构建列表的是递归。 So just call it build . 所以就称它为build It's also perfectly fine to define predicates with the same name but a different number of parameters. 定义具有相同名称但参数数量不同的谓词也很好。

I've also named Lout as Zs as this helps indicate that it's a list - prolog doesn't usually care about inputs or outputs anyway. 我也将Lout命名为Zs因为这有助于表明它是一个列表-Prolog通常并不关心输入或输出。 You could run the query ?- build(6, [[5, 1], [4, 2], [3, 3], [2, 4], [1, 5]]). 您可以运行查询?- build(6, [[5, 1], [4, 2], [3, 3], [2, 4], [1, 5]]). and you'll get success even though you've sent the output list in as an input parameter. 即使将输出列表作为输入参数发送,您也将获得成功。

a more idiomatic way: 更惯用的方式:

listFromLoop(U,W) :- U_ is U-1,
    findall([I,J],(between(1,U_,J),I is U_-J+1),W).

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM