프롤로그-목록에 재귀 적으로 숫자 추가

Nov 14 2020

저는 프롤로그를 배우기 시작했고 재귀 적 개념으로 머리를 감싸는 데 어려움을 겪고 있습니다. 지금은 연습 목적으로 만 목록에 10 개의 숫자를 추가 한 다음 그 목록을 인쇄하는 프로그램을 작성하려고합니다.

이 프로그램에 대한 자체 부과 규칙은 목록에 숫자를 추가하기 위해 다른 술어를 호출하는 주 술어에서 목록이 '선언'되어야한다는 것입니다 (Prolog의 올바른 단어인지 확실하지 않습니다).

이것은 내가 지금까지 가지고있는 것이며 , 언어에서 허용되지 않는 술어 List의 끝에서 재정의하려고하기 때문에 작동하지 않을 것임을 알고 addToList있습니다.

% 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

이 프로그램은 다음으로 시작됩니다.

printList(List).

제대로 작동하도록 작성한 깨진 프로그램을 변경하는 간단한 방법이 있습니까? 에 저장된 번호를 얻는 방법을 잃어 버렸습니다 List.

답변

3 rajashekar Nov 14 2020 at 12:48

절차 적으로 생각하고 있으며 프롤로그에서는 변수를 변경할 수 없습니다. 목록을 직접 구성하려고합니다. 프롤로그 스타일에서는 원하는 목록의 제약 조건을 선언하려고합니다. 경우 nlist/2다음 N 번호 목록을 제공하는 술어가 정확히이 속성의 무엇? nlist(0, []).그리고 만약 nlist(N, Xs)그렇다면 nlist(N+1, [N+1 | Xs]). 그래서 당신은 이것들을 작성하고 프롤로그가 구성을 처리하도록합니다.

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

재귀 호출이 어떻게 발생하는지 혼란 스러우면 trace/0또는을 사용해보십시오 trace/1. 다음 추적에서 호출이 수행되는 방식을 볼 수 있습니다. 를 호출하여 얻을 수 있습니다 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]

보다 절차적인 스타일 코드는 다음과 같습니다.

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).

이것은 중간 매개 변수가 누산기를 제공합니다. 11에 도달하면 누산기가 답입니다.

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

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

샘플 추적과 그들 사이의 차이 봐 nlistaddToList. 차이점과 왜 발생하는지 파악하십시오.

?- 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] 
1 ReemaQKhan Nov 15 2020 at 00:04

내 해결책은 다음과 같습니다.

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]

술어는 시작 번호와 증분을 원하는 횟수를 사용하여 시리즈를 인쇄하는 데 사용할 수 있습니다. 매우 쉬운 방법은 카운터를 사용하는 것입니다. 첫 번째 술어는 시작 번호와 목록에있는 것이 무엇이든 상관없이 카운터가 0에 도달하면 프로그램이 중단되어야한다는 것입니다. 두 번째 술어에는 시작 번호와 시작 번호로 목록을 시작해야 함을 알리는 목록과 마지막으로 카운터가 있습니다. 다음으로 시작 번호를 1 씩 증가시킵니다. 카운터를 1 감소시킵니다. 그런 다음 술어에 새 값을 제공하여 모든 것을 다시 실행합니다.

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