SWI-Prolog를 사용하여 누산기없이 0에서 n까지 증가 / 계산할 수 있습니까?

Nov 16 2020

numlist / 3와 같은 목록이 아니라 한 번에 하나의 값이 반환되는 0에서 N까지 계산하려고합니다. 두 개의 술어 문으로 재귀를 사용할 수 있다고 생각하지만 내가 찾고있는 방식으로 작동하는 중지 조건을 생각해 냈습니다.

iterate(0,_).
iterate(X,N) :- iterate(Y,N), Y < N, X is Y + 1.

내 현재 이해하에 첫 번째 술어는 iterate (X, N)를 호출 할 때 항상 첫 번째 값으로 0을 리턴하고 두 번째는 다음 값을 제공하는 재귀 호출을 반복합니다.

내가 겪은 문제는 올바르게 N까지 계산되지만 스택 제한에 도달한다는 것입니다. 이것은 술어 시작 부분에 재귀 호출을하고 나중에 반환 결과를 확인하기 때문이라고 생각합니다.

주요 단절은 Prolog가 술어를 다루는 방법에 대한 나의 이해인 것 같습니다. 내가 읽은 바에 따르면 Prolog는 다음과 같이 두 번째 호출을 처리하는 것 같습니다.

iterate(Y,N) ⋀ (Y < N) ⋀ (X is Y + 1)

나는 이것이 Y <N이 거짓을 반환하면 재귀 호출이 중지된다는 것을 의미한다고 생각했습니다. 이 시점에서 저는 술어에서 재귀 호출 위치의 몇 가지 변형을 시도했습니다. 항상 마지막에 X의 최종 값이 선언되어 값 선언이 있어야하는 것처럼 보입니다.

또한 ISO-Prolog에 (;) / 2 (if-then-else)가 있음을 확인했지만이 경우에 적용 할 수있는 SWI-Prolog에서 도움이 될만한 유사한 항목을 찾지 못했습니다.

SWI-Prolog에서 두 개의 술어 문으로 이것이 가능하다고 생각하는 것이 잘못입니까?

편집 : 나는 추가 도전을 위해 누산기없이 이것을 할 계획입니다.

답변

1 WillemVanOnsem Nov 16 2020 at 05:55

나는 이것이 Y < Nfalse를 반환하면 재귀 호출이 중지 된다는 것을 의미한다고 생각했습니다 .

프롤로그는 왼쪽에서 오른쪽으로 (또는 위에서 아래로) 평가하므로 먼저 재귀 호출을 만들고 해당 호출이 성공하면 다음 부분을 확인 Y < N하므로 그렇게 사용하면 실제로 중단됩니다. 무한 루프에서, 더 많은 재귀 호출을 계속할 것이기 때문에 결국 모두 Y < N테스트에 실패 할 것이지만 Prolog가 새로운 재귀 호출을 만드는 것을 막는 것은 없습니다.

따라서 주문을 다음과 같이 바꿀 수 있습니다.

iterate(I, J, I) :-
    I =< J.
iterate(I, J, R) :-
    I < J,
    I1 is I + 1,
    iterate(I1, J, R).

그러면 다음이 제공됩니다.

?- iterate(10, 15, R).
R = 10 ;
R = 11 ;
R = 12 ;
R = 13 ;
R = 14 ;
R = 15 ;
false.

따라서 범위 [I .. J]에서는 I해당 범위의 구성원 (firs 절)이고 if I < J요소 [I+1 .. J]도 해당 범위의 구성원 (두 번째 절)임을 의미합니다.

ReemaQKhan Nov 16 2020 at 05:50

내 접근 방식은 다음과 같습니다.

printSeries(_,0):-!.
printSeries(S,C):-
    S1 is S+1,
    C1 is C-1,
    writeln(S),
    printSeries(S1,C1). 

?-printSeries(1,10).
1
2
3
4
5
6
7
8
9
10
1true

?-printSeries(15,10).
15
16
17
18
19
20
21
22
23
24
1true

?-printSeries(0,10).
0
1
2
3
4
5
6
7
8
9
1true



?-printSeries(0,5).
0
1
2
3
4
1true
DavidTonhofer Nov 16 2020 at 05:59

그것은 하나에 많은 질문입니다.

프로그램부터 시작하겠습니다.

따라서 0에서 최대까지 세고 싶을 것 N입니다.

한 번에 하나의 값 반환

Prolog 술어가 "값을 반환"하지 않기 때문에 그것이 의미하는 바를 판단하는 것은 어렵습니다. 성공하거나 실패 (또는 예외를 던짐)하고 ,. 다음에 사용할 다음 술어의 값에 변수를 바인딩 할 수 있습니다 .

그러나 우리 가 숫자의 순서 를 인쇄 하고 싶다고 가정 해 봅시다 . 그때:

print_them(Max) :-               % Predicate to "count up to Max"
   pth2(Max,0).                  % It calls a a helper predicate that counts ...
                                 % ... up to "Max" starting at 0

% ---
% pth2(+Max,+C)                  % Predicate: "Count to Max starting at C"
% ---

pth2(Max,Max) :-                     % We will stop with Max == C
   format("I'm at max: ~d\n",[Max]). % Just print something in that case.

pth2(Max,C) :-                       % Case of Max not necessarily being C
   C < Max,                          % "guard": only proceed "rightwards" if C < Max
   format("I'm at ~d\n",[C]),        % and then some printing
   Cp is C + 1,                      % Evaluation: C is known, so compute a Cp
   pth2(Max,Cp).                     % ...and then count to Max from Cp.

pth2(Max,C) :-                       % Case of Max not necessarily being C, again
   C > Max,                          % "guard": only proceed "rightwards" if C > Max
   throw("C exceeds Max").           % And then throw an exception

위 내용이 더 명확합니까?

그래서 :

?- print_them(12).
I'm at 0
I'm at 1
I'm at 2
I'm at 3
I'm at 4
I'm at 5
I'm at 6
I'm at 7
I'm at 8
I'm at 9
I'm at 10
I'm at 11
I'm at max: 12
true ;              <--- success but maybe there are other solutions?
false.              <--- nah, actually not
TA_intern Nov 16 2020 at 16:43

정말로 필요한 것은 between/3. 이렇게 :

?- between(0, 4, X).
X = 0 ;
X = 1 ;
X = 2 ;
X = 3 ;
X = 4.

?- forall(between(0, 4, X), format("~w~n", [X])).
0
1
2
3
4
true.

between/3내장되어 있습니다. 자신을 프로그래밍하고 모든 가장자리 사례를 다루는 것은 상대적으로 어렵습니다.

결과를 필터링 할 수도 있습니다 (예 : 홀수 만).

?- between(0, 9, X), X rem 2 =:= 1.
X = 1 ;
X = 3 ;
X = 5 ;
X = 7 ;
X = 9.

또는 순진하게 소수만 인쇄합니다.

?- between(1, 9, X), succ(X0, X), forall(between(2, X0, Y), X rem Y =\= 0).
X = 1 ;
X = 2 ;
X = 3 ;
X = 5 ;
X = 7 ;
false.
TheWubMunzta Nov 18 2020 at 11:52

나는 초기 코드 스 니펫을 조정하여 누산기없이 0에서 n까지 계산하는 방법을 알아 냈습니다. David Tonhofer가 명시된 문제를 해결하는 동안 추가 된 도전 목표를 해결하는 솔루션을 게시하고 싶습니다.

iterate(0,_).
iterate(X,N) :- iterate(Y,N), (Y < N -> X is Y + 1; !).

이 코드를 통해 iterate (X, N)를 호출 할 수 있습니다. N은 실수이고 X는 변수이며 X는 0에서 N까지의 모든 값을 포함합니다. 이를 통해 방정식에 대해 0에서 N까지의 모든 정수 값을 테스트하고 솔루션을 찾을 수 있습니다.

iterate (X, N)이 호출되면 아래 값을 반환합니다.

?- iterate(X,10).
X = 0 ;
X = 1 ;
X = 2 ;
X = 3 ;
X = 4 ;
X = 5 ;
X = 6 ;
X = 7 ;
X = 8 ;
X = 9 ;
X = 10 ;
true.