简体   繁体   English

Prolog - 递归地将数字附加到列表中

[英]Prolog - Recursively append numbers to a list

I am just starting to learn Prolog, and I am having troubles wrapping my head around recursive concepts.我刚刚开始学习 Prolog,并且在递归概念上遇到了麻烦。 Right now, solely for the purpose of practice, I am trying to write a program that appends 10 numbers to a list and then prints out that list.现在,仅出于练习的目的,我正在尝试编写一个程序,将 10 个数字附加到一个列表中,然后打印出该列表。

The self-imposed rule for this program is that the list has to be 'declared' (I am not sure if that is the correct word for Prolog) in a main predicate, which calls another predicate to append numbers to the list.这个程序的自我强加规则是必须在主谓词中“声明”列表(我不确定这是否是 Prolog 的正确词),它调用另一个谓词将数字附加到列表中。

This is what I have so far, and I know it won't work because I am trying to redefine List at the end of the addToList predicate, which is not allowed in the language.到目前为止,这是我所拥有的,我知道它不会起作用,因为我试图在addToList谓词的末尾重新定义List ,这在语言中是不允许的。

% Entry point that declares a list (`List`) to store the 10 numbers
printList(List) :-
    addToList(0, List),
    writeln(List).

% Base case - once we hit 11 we can stop adding numbers to the list
addToList(11, _).

% First case - this predicate makes adding the first number easier for me...
addToList(0, List) :-
    append([], [0], NewList),
    addToList(1, NewList),
    append([],  NewList, List). % This is valid, but List will just be [0] I think..

% Cases 1-10
addToList(Value, List) :-
    append(List, [Value], NewList),
    NextVal is Value+1,
    addToList(NextVal, NewList),
    append([], NewList, List). % This is INVALID since List is already defined

This program would be started with:该计划将开始于:

printList(List).

Is there a simple way to change up the broken program I have written up to make it work correctly?有没有一种简单的方法可以更改我编写的损坏程序以使其正常工作? I am super lost on how to get the numbers stored in List .我对如何获取存储在List的数字感到非常迷茫。

You are thinking procedurally, in prolog you cannot change variables.你在程序上思考,在序言中你不能改变变量。 You are trying to construct the list yourself.您正在尝试自己构建列表。 In prolog-style you try to declare the constraints of the list you want.在 prolog 样式中,您尝试声明所需列表的约束。 If nlist/2 is a predicate that gives a list of N numbers then what exactly are it's properties?如果nlist/2是一个给出 N 个数字列表的谓词,那么它的属性究竟是什么? nlist(0, []). and if nlist(N, Xs) then nlist(N+1, [N+1 | Xs]) .如果nlist(N, Xs)nlist(N+1, [N+1 | Xs]) So you just write these and let prolog take care of the construction.因此,您只需编写这些并让 prolog 负责构建。

nlist(0, []).
nlist(N, [N | Xs]) :-
    N>0, N1 is N-1,
    nlist(N1, Xs).

If you are confused how the recursion calls are taking place, try using trace/0 or trace/1 .如果您对递归调用的发生方式感到困惑,请尝试使用trace/0trace/1 You can see how the calls are being done in the following trace.您可以在以下跟踪中看到调用是如何完成的。 You can get this by calling trace(nlist) .您可以通过调用trace(nlist)获得此信息。

?- nlist(3, X).
 T Call: nlist(3, _78)
 T Call: nlist(2, _902)
 T Call: nlist(1, _1464)
 T Call: nlist(0, _2026)
 T Exit: nlist(0, [])
 T Exit: nlist(1, [1])
 T Exit: nlist(2, [2, 1])
 T Exit: nlist(3, [3, 2, 1])
X = [3, 2, 1]

A more procedural style code will be as follows更程序化风格的代码如下

addToList(11, A, A).

% Cases 1-10
addToList(Value, List, NewList) :-
    Value < 11,  append(List, [Value], Temp),
    NextVal is Value+1,
    addToList(NextVal, Temp, NewList).

This gives the middle parameter is the accumulator.这给出了中间参数是累加器。 When you reach 11 the accumulator is the answer.当您达到 11 时,累加器就是答案。

?- addToList(1, [], X).
X = [1, 2, 3, 4, 5, 6, 7, 8, 9|...] 

?- addToList(5, [], X).
X = [5, 6, 7, 8, 9, 10] 

Look at the sample trace and the difference between them in nlist and addToList .查看示例跟踪以及它们在nlistaddToList中的nlist Try to figure out the differences and why the are happening.尝试找出差异以及为什么会发生这些差异。

?- addToList(7, [], X).
 T Call: addToList(7, [], _33565254)
 T Call: addToList(8, [7], _33565254)
 T Call: addToList(9, [7, 8], _33565254)
 T Call: addToList(10, [7, 8, 9], _33565254)
 T Call: addToList(11, [7, 8, 9, 10], _33565254)
 T Exit: addToList(11, [7, 8, 9, 10], [7, 8, 9, 10])
 T Exit: addToList(10, [7, 8, 9], [7, 8, 9, 10])
 T Exit: addToList(9, [7, 8], [7, 8, 9, 10])
 T Exit: addToList(8, [7], [7, 8, 9, 10])
 T Exit: addToList(7, [], [7, 8, 9, 10])
X = [7, 8, 9, 10] 

Here is my solution:这是我的解决方案:

printSeries(_,[],0):-!.
printSeries(S,[S|T],C):-
    S1 is S+1,
    C1 is C-1,
    printSeries(S1,T,C1).

?- printSeries(7,L,5).
L = [7, 8, 9, 10, 11]

The predicate can be used to print any series using a starting number and how many times one wants to increment it.谓词可用于使用起始编号以及想要增加它的次数来打印任何系列。 A very easy approach is using counter.一个非常简单的方法是使用计数器。 The first predicate is saying that regardless of the starting number, and whatever is in the list, if the counter reaches 0 the program should cut (meaning stop).第一个谓词是说无论起始编号如何,也不管列表中的内容如何,​​如果计数器达到 0,程序应该停止(意味着停止)。 The second predicate we have the starting number, and the list to which we are telling it that you have to start the list with the starting number, and lastly the counter.第二个谓词我们有起始编号,以及我们告诉它必须以起始编号开始列表的列表,最后是计数器。 Next we increment the starting number by 1. Decrease the counter by 1. Then redo everything by giving the new values to the predicate.接下来,我们将起始数字加 1。将计数器减 1。然后通过为谓词提供新值来重做所有事情。

?-printSeries(1,L,10).
L = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

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

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