반복이 재귀를 대체 할 수 있습니까? 된 스레드 가있었습니다 . 지금은

나는 스택 오버플로를 보았습니다. 예를 들어 여기 , 여기 , 여기 , 여기 , 여기 그리고 여기 에 언급하고 싶지 않은 다른 것들, “재귀를 사용하는 모든 프로그램은 반복만을 사용하는 프로그램으로 변환 될 수 있습니다.”

가능하다고 답한 고도로 공감 된 을 가진 고도로 공감 된 스레드 가있었습니다 .

지금은 그들이 틀렸다는 말이 아닙니다. 그 대답은 컴퓨팅에 대한 나의 빈약 한 지식과 이해에 반하는 것입니다.

나는 모든 반복 함수가 재귀로 표현 될 수 있다고 생각하며 wikipedia에는 ​​그 효과에 대한 진술이 있습니다. 그러나 나는 그 대화가 사실인지 의심합니다. 우선, 기본이 아닌 재귀 함수를 반복적으로 표현할 수 있을지 의심됩니다.

또한 과잉 연산이 반복적으로 표현 될 수 있을지는 의문입니다.

@YuvalFIlmus 내 질문에 대한 그의 대답 (내가 이해하지 못함)에서 수학 연산 시퀀스를 추가 시퀀스로 변환 할 수는 없다고 말했습니다.

YF의 대답이 실제로 정확하다면 (그것이 맞지만 그의 추론이 내 머리 위에 있음) 이것이 모든 재귀가 반복으로 변환 될 수있는 것은 아닙니다. 모든 재귀를 반복으로 변환 할 수 있다면 모든 작업을 일련의 추가로 표현할 수 있기 때문입니다.

내 질문은 이것입니다 :

모든 재귀를 반복으로 변환 할 수 있습니까?

밝은 고등학생 또는 1 학년생이 이해할 수있는 답변을 제공하십시오. 감사합니다.

추신 : 나는 원시 재귀가 무엇인지 모른다.

PPS : 대답이 ‘예’인 경우, 예를 들어 비원시 재귀 함수의 반복 버전을 작성할 수 있습니까? 예를 들어 Ackermann이 대답합니다. 이해하는 데 도움이 될 것입니다.



답변

반복 과 무제한 메모리로 재귀를 대체 할 수 있습니다 .

반복 (예 : while 루프)과 유한 한 양의 메모리 만있는 경우 유한 한 오토 마톤 만 있으면됩니다. 유한 한 양의 메모리를 사용하면 계산에는 유한 한 수의 단계가 있으므로 유한 한 오토 마톤으로 모든 단계를 시뮬레이션 할 수 있습니다.

무한한 메모리가 있으면 거래가 변경됩니다. 이 무한한 기억은 많은 표현력을 가질 수있는 많은 형태를 취할 수 있습니다. 예를 들어, 튜링 머신은 간단하게 유지합니다. 단일 테이프가 있고 컴퓨터는 한 번에 한 단계 씩 테이프에서 앞뒤로 만 이동할 수 있지만 재귀 기능으로 수행 할 수있는 모든 작업을 수행하기에 충분합니다.

튜링 머신은 필요에 따라 확장되는 추가 스토리지를 갖춘 이상적인 컴퓨터 모델 (유한 상태 머신)로 볼 수 있습니다. 테이프에 한정된 경계가있을뿐만 아니라 입력이 주어진 경우에도 필요한 테이프의 양을 확실하게 예측할 수없는 것이 중요합니다. 입력에서 필요한 테이프의 양을 예측 (예 : 계산) 할 수있는 경우 최대 테이프 크기를 계산 한 다음 현재 유한 테이프를 포함한 전체 시스템을 유한 상태 머신으로 처리하여 계산을 중지할지 여부를 결정할 수 있습니다. .

컴퓨터로 튜링 머신을 시뮬레이션하는 다른 방법은 다음과 같습니다. 테이프의 시작 부분을 메모리에 저장하는 컴퓨터 프로그램으로 Turing 기계를 시뮬레이션하십시오. 계산이 메모리에 맞는 테이프 부분의 끝에 도달하면 컴퓨터를 더 큰 컴퓨터로 교체하고 계산을 다시 실행하십시오.

이제 컴퓨터를 사용하여 재귀 계산을 시뮬레이션한다고 가정하십시오. 재귀 함수를 실행하는 기술은 잘 알려져 있습니다. 각 함수 호출 에는 스택 프레임 이라는 메모리가 있습니다. 결정적으로 재귀 함수는 변수를 전달하여 여러 호출을 통해 정보를 전파 할 수 있습니다. 컴퓨터에서의 구현 측면에서 볼 때 이는 함수 호출이 ( * ) * 부모 호출 의 스택 프레임에 액세스 할 수 있음을 의미합니다 .

컴퓨터는 유한 상태 머신 (엄청나게 많은 상태를 가지고 있지만 여기서 계산 이론을 수행하고 있기 때문에 중요한 것은 유한하다는 것) 인 프로세서는 유한 메모리와 결합 된 프로세서입니다. 마이크로 프로세서는 하나의 거대한 while 루프를 실행합니다. “전원이 켜져있는 동안 메모리에서 명령을 읽고 실행합니다.” (실제 프로세서는 그보다 훨씬 복잡하지만 계산할 수있는 것, 속도 및 편리성에 영향을 미치지 않습니다.) 컴퓨터는 반복을 제공하기 위해이 while 루프만으로 재귀 함수를 실행할 수 있습니다. 마음대로 메모리 크기를 늘리는 기능을 포함하여 액세스 메모리에 액세스합니다.

재귀를 기본 재귀로 제한하면 반복을 경계 반복으로 제한 할 수 있습니다 . 즉, 예기치 않은 실행 시간으로 while 루프를 사용하는 대신 루프 시작 부분에 반복 횟수가 알려진 루프에 for 루프를 사용할 수 있습니다. 반복 횟수는 프로그램 시작 부분에 알려지지 않았을 수 있습니다. 자체 루프는 이전 루프에 의해 계산 될 수 있습니다.

여기서는 증거를 스케치하지는 않지만 기본 재귀에서 전체 재귀로, for 루프에서 while 루프로 이동하는 것 사이에는 직관적 인 관계가 있습니다. 두 경우 모두 사전에 알지 못합니다. 중지. 완전 재귀를 사용하면 최소화 연산자를 사용하여 조건을 만족하는 매개 변수를 찾을 때까지 계속 진행합니다. while 루프의 경우 루프 조건이 충족 될 때까지 계속 진행하면됩니다.

forwhile

n


답변

페치 실행 무한 반복을 사용하여 임의의 프로그램을 실행하는 CPU에서 목격 한대로 모든 재귀를 반복으로 변환 할 수 있습니다. 이것은 Böhm-Jacopini 정리 의 한 형태입니다 . 또한 많은 Turing-complete 계산 모델에는 재귀가 없습니다 (예 : Turing 기계카운터 기계) .

기본 재귀 함수 는 바운드 반복을 사용하는 프로그램에 해당합니다. 즉, 루프가 미리 실행되는 반복 횟수를 지정해야합니다. Ackermann 함수는 원시 재귀가 아니기 때문에 경계 반복은 일반적으로 재귀를 시뮬레이션 할 수 없습니다. 그러나 무한 반복은 부분적으로 계산 가능한 기능을 시뮬레이션 할 수 있습니다.


답변

a(n,m)

s

push⁡(s,x)

x

x←pop⁡(s)

empty⁡(s)

Ackermann(n0,m0):





  • s=∅

    (빈 스택 초기화)

  • push⁡(s,n0)


  • push⁡(s,m0)


  • while(true):


    • m←pop⁡(s)


    • if(empty⁡(s)):


      • return m

        (루프를 종료합니다)

    • n←pop⁡(s)


    • if(n=0):


      • push⁡(s,m+1)


    • else if(m=0):


      • push⁡(s,n−1)


      • push⁡(s,1)


    • else:


      • push⁡(s,n−1)


      • push⁡(s,n)


      • push⁡(s,m−1)

나는 이것을 실론에서 구현했다 . 원한다면 WebIDE에서 실행할 수있다. 루프의 각 반복이 시작될 때 스택을 출력합니다.

물론 이것은 암시 적 호출 스택을 재귀에서 매개 변수 및 반환 값이있는 명시 적 스택으로 옮겼습니다.


답변

이미 좋은 답변이 있지만 (이것도 경쟁하기를 희망하지는 않지만)이 간단한 설명을하고 싶습니다.

재귀는 단지 런타임 스택의 조작입니다. 재귀는 (재귀 함수의 새로운 호출을 위해) 새로운 스택 프레임을 추가하고, 재귀는 (재귀 함수의 방금 완성 된 혁신을 위해) 스택 프레임을 제거합니다. 재귀는 결국 모든 프레임 프레임이 종료되고 (바람직하게!) 결과가 호출자에게 반환 될 때까지 일부 스택 프레임이 추가 / 제거됩니다.

이제 자신의 스택을 만들고 스택으로 푸시하여 재귀 함수 호출을 대체하고 스택을 팝핑하여 재귀 함수에서 반환을 대체하고 스택이 비어있을 때까지 실행되는 while 루프가 있으면 어떻게됩니까?


답변

내가 알 수있는 한, 내 경험으로는 반복으로 모든 재귀를 구현할 수 있습니다. 위에서 언급했듯이 재귀는 개념적으로 무제한이지만 실제로 제한적인 스택을 사용합니다 (스택 오버플로 메시지를 받았습니까?). 저의 초창기 (마지막 밀레니엄 마지막 세기의 3/4 분기)에 재귀 알고리즘을 구현하는 비 재귀 언어를 사용하고 있었으며 아무런 문제가 없었습니다. 그래도 어떻게 증명할 지 잘 모르겠습니다.