재귀 제거-장면 뒤의 이론을 살펴보십시오.


10

나는이 사이트를 처음 접했고이 질문은 확실히 연구 수준은 아니지만 오. 저는 소프트웨어 엔지니어링에 약간의 배경 지식이 있고 CSTheory에는 거의 경험이 없지만 매력적입니다. 간단히 말해서이 사이트에서이 질문이 수용 가능한 경우 다음에 대한 자세한 답변을 원합니다.

따라서 모든 재귀 프로그램에는 반복적 인 아날로그가 있다는 것을 알고 있으며 "시스템 스택"과 비슷한 것을 유지하고 반송 주소 등의 환경 설정을 푸시하여 제공되는 대중적인 설명을 이해합니다. .

좀 더 구체적으로, 나는 체인 호출하는 함수가있는 경우 어떻게이 공식이이 진술을 증명하는지 알고 싶습니다 . 또한, F iF j를 호출 할 수있는 조건문이있는 경우 어떻게해야 합니까? 즉, 잠재적 인 함수 호출 그래프에는 일부 강하게 연결된 구성 요소가 있습니다.F0F1FiFi+1FnF0FiFj

반복적 인 변환기를 반복적으로 사용하여 이러한 상황을 처리하는 방법을 알고 싶습니다. 그리고 앞에서 언급 한 손으로 쓴 설명이이 문제에 대해 충분한가? 그렇다면 왜 어떤 경우에는 재귀를 쉽게 제거 할 수 있습니까? 특히 이진 트리의 사전 주문 통과에서 재귀를 제거하는 것은 정말 쉽습니다. 표준 인터뷰 질문이지만 포스트 주문의 경우 재귀를 제거하는 것은 항상 악몽이었습니다.

내가 정말로 묻는 것은 가지 질문입니다.2

(1) 재귀를 반복으로 변환 할 수 있다는보다 공식적인 설득력있는 증거가 있습니까?

(2)이 이론이 실제로 존재한다면, 왜 예를 들어, 더 쉽게 사전 주문을 반복 하고 , 너무 많은 주문을 반복 하는가? (제한된 정보 이외)


1
iteratizing라는 단어처럼 :)
Akash Kumar

완전히 이해했는지 확실하지 않지만 재귀가 어딘가에서 끝나면 실제로 자신의 스택을 사용하여 시스템 스택을 시뮬레이션 할 수 있습니다. 파트 (2)의 경우, 계산 복잡성 측면에서 문제는 다르지 않습니다.
singhsumit

이 질문은 컴퓨터 과학에 가장 적합했을 것입니다. 아직 게시되지 않은 사이트 입니다. 두 번째 질문에 대해 왜 그것이 더 어렵다고 생각하는지 자세히 설명 할 수 있습니까? 프로세스는 거의 동일해야합니다.
Raphael

귀하의 의견에 모두 감사합니다-할 일이 꽤 있다고 생각합니다.
Itachi Uchiha

@Raphael-포스트 주문을 반복하는 것이 어렵다고 생각하는 이유에 대한 한 가지 의견 (내가 할 수 없다는 것 외에도). 재귀 제거에 대한 기사를 읽고 꼬리 재귀 함수라는 것을 발견했습니다. 반복하기가 더 쉽습니다. 나는 이것이 왜 이것이 사실인지 공식적으로 이해하지 못한다. 하지만 내가 추가해야 할 또 다른 것이 있습니다. 나는 postorder를 반복하는 것이 하나의 스택이 아니라 두 개의 스택을 필요로하지만 세부 사항을 모릅니다. 그리고 지금 나는 길을 잃었습니다-왜이 두 통과 모드의 차이점입니까? 왜 꼬리 재귀가 다루기 쉬운가?
Itachi Uchiha

답변:


6

올바르게 이해하면 다른 함수 호출이 아닌 자신에게 함수를 변환하는 것이 분명합니다.

"콜 체인" 가 있다고 가정 합니다. 우리가 더 나아가 F 1 , , F 라고 가정하면FF1FnF 이 재귀 적이 지 않다고(이미 변환 했으므로)모든 호출을 F 의 정의로인라인할 수 있으므로 이미 처리 할 수있는 직접 재귀 함수가됩니다.F1,,FnF

어떤 경우에 실패 자체되는 재귀 호출 체인이 F가 발생합니다, 즉 F JF FjF . 이 경우, 우리는상호 재귀를가지고 있는데,이것은 또 다른 트릭을 제거해야합니다. 아이디어는 두 기능을 동시에 계산하는 것입니다. 예를 들어 사소한 경우 :FjFF제이

f(0) = a
f(n) = f'(g(n-1))

g(0) = b
g(n) = g'(f(n-1))

f'g'비 재귀 함수 (또는 적어도 무관 f하고 g)된다

h(0) = (a,b)
h(n) = let (f,g) = h(n-1) in (f'(g), g'(f)) end

f(n) = let (f, _) = h(n) in f end
g(n) = let (_, g) = h(n) in g end

이것은 자연스럽게 더 많은 기능과 더 복잡한 기능으로 확장됩니다.


기꺼이 도와 드리겠습니다. 옆에있는 확인 표시를 클릭하여 좋아하는 답변을 수락하십시오.
Raphael

1
Raphel, 귀하의 트릭은 두 재귀 함수가 동일한 유형의 인수를 허용하는 경우에만 작동합니다. 경우 fg유형의 다른 종류를 받아,보다 일반적인 트릭이 필요하다.
Andrej Bauer

@ AndrejBauer 좋은 관찰, 나는 그것을 완전히 놓쳤다. 나는 라파엘의 접근법을 정말로 좋아했지만 일반적인 경우에서 관찰 한 것처럼 다른 아이디어가 필요할 것입니다. 다른 제안을 할 수 있습니까?
Itachi Uchiha

fgn1n2

글쎄, 그것을하는 방법에 대한 내 대답을 참조하십시오.
Andrej Bauer

8

그렇습니다. 재귀가 반복으로 바뀔 수 있다는 확실한 이유가 있습니다. 이것이 소스 코드를 기계 언어로 번역 할 때 모든 컴파일러가하는 일입니다. 이론적으로 Dave Clarke의 제안을 따라야합니다. 재귀를 비 재귀 코드로 변환하는 실제 코드를 보려면 살펴보십시오.machine.ml PL Zoo 의 MiniML 언어를 ( loop실제로 코드를 실행하는 맨 아래 의 함수는 꼬리 재귀이므로 실제 루프로 간단하게 변환됩니다.)

하나 더. MiniML은 상호 재귀 함수를 지원하지 않습니다. 그러나 이것은 문제가되지 않습니다. 함수 사이에 상호 재귀가있는 경우

f1:A1B1
f2:A2B2
fn:AnBn

재귀는 단일 재귀 맵으로 표현 될 수 있습니다.

f:A1++AnB1++Bn,

8

SECD 머신 을보고 싶을 수도 있습니다 . 기능적 언어 (모든 언어 일 수 있음)는 스택의 인수를 넣거나, 새로운 함수를 호출하는 등의 작업을 관리하는 일련의 명령어로 변환되며, 모두 간단한 루프로 관리됩니다.
재귀 호출은 실제로 호출되지 않습니다. 대신 호출되는 함수 본문의 명령어가 스택에 배치되어 실행됩니다.

관련된 접근 방식은 CEK 시스템입니다 .

이것들은 오랫동안 주변에 있었으므로 거기에 많은 작업이 있습니다. 물론 작동한다는 증거가 있으며 프로그램을 SECD 명령어로 "컴파일"하는 절차는 프로그램 크기에 비례합니다 (프로그램에 대해 생각할 필요는 없습니다).

내 대답의 요점은 원하는 것을 수행하는 자동 절차가 있다는 것입니다. 불행히도, 변환이 프로그래머가 즉시 해석하기 쉬운 것들에 관한 것은 아닙니다. 핵심은 프로그램을 반복하고 싶을 때 반복 된 함수 호출에서 돌아올 때 프로그램이해야 할 일을 스택에 저장해야한다는 것입니다 (연속이라고합니다). 꼬리 재귀 함수와 같은 일부 함수의 경우 연속성이 간단합니다. 다른 사람들에게는 연속을 매우 복잡하게 만들 수 있습니다. 특히 직접 인코딩 해야하는 경우 특히 그렇습니다.


나는 정직 할 것이다. 모든 재귀 적 프로그램을 반복하는 이유와 방법을 이해하고 싶습니다. 그러나 나는 종이를 통해 읽는 것이 어렵다는 것을 알았습니다. 그들은 일반적으로 내게 접근 할 수 없습니다. 나는 내가 질문에서 이야기 한 "handwavy"설명보다 더 깊은 이유를 원한다는 것을 의미한다. 그러나 나는 또한 나에게 새로운 통찰력을주는 무언가에 만족한다 – 그것은 그것의 엉뚱한 세부 사항에 대한 완전한 증거 일 필요는 없다
Itachi Uchiha

[cntd] 하나의 프로그램을 다른 프로그램보다 쉽게 ​​반복하는 이유를 알려주는 증거가 있다면 좋겠다는 뜻입니다. 그러나 어떤 의미에서 재귀 대 반복 변환기는 어떤 재귀 프로그램이 입력으로 사용 되더라도 작동해야합니다. 확실하지는 않지만 그러한 변환기를 만드는 것이 중지 문제만큼 힘들 수 있습니까? 나는 단지 여기에서 추측하고있다. 그러나 나는 반복적 인 변환기를 반복적으로 사용하고 싶습니다. 그렇다면 다른 재귀 적 프로그램을 반복하는 것의 본질적인 복잡성을 설명하고 싶습니다. 확실하지 않지만 질문을 편집해야합니까? 내 질문이 분명합니까?
Itachi Uchiha

@ ItachiUchiha-귀하의 문제를 결정할 수 없다고 생각합니다. Andrej Bauer의 답변을보십시오. 그는 모든 컴파일러가 소스 코드를 기계 언어로 변환 할 때이를 수행한다고 언급했다. 또한 MiniM (a) l 언어에서 재귀를 비 재귀로 변환하는 실제 코드를 볼 수 있다고 덧붙입니다. 이것은 재귀를 "결정화"하는 결정 절차가 있음을 분명히 나타냅니다. 재귀 제거의 본질적 (개념적) 난이도 / 복잡성에 대해 잘 모르겠습니다. 나는이 질문을 매우 명확하게 이해하지 못하지만 재미있게 보입니다. 아마 당신은 더 나은 답변을 얻기 위해 질문을 편집 할 수 있습니다
Akash Kumar

내 대답의 요점은 원하는 것을 수행하는 자동 절차가 있다는 것입니다. 불행히도, 변환이 프로그래머가 즉시 해석하기 쉬운 것들에 관한 것은 아닙니다. 핵심은 프로그램을 반복하고 싶을 때 반복 된 함수 호출에서 돌아올 때 프로그램이해야 할 일을 스택에 저장해야한다는 것입니다 (연속이라고합니다). 꼬리 재귀 함수와 같은 일부 함수의 경우 연속성이 간단합니다. 다른 사람들에게는 연속을 매우 복잡하게 만들 수 있습니다. 특히 직접 인코딩 해야하는 경우 특히 그렇습니다.
Dave Clarke

6

Q : "재귀를 반복으로 변환 할 수 있다는 공식적인 증거가 있습니까?"

A : Turing Machine의 Turing 완전성 :-)

놀랍게도 Turing 등가 랜덤 액세스 저장 프로그램 (RASP) 머신 모델 은 실제 마이크로 프로세서가 작동하는 방식에 가깝고 명령 세트에는 조건부 점프 만 포함됩니다 (재귀 없음). 코드를 자체적으로 수정하는 기능은 서브 루틴 및 재귀 호출 을 구현 하는 작업을 보다 쉽게 ​​만듭니다.

난 당신이 "에 많은 논문 / 기사를 찾을 수 있다고 생각 반복적 인 변환 재귀 "(데이브의 답변을 참조하거나 구글 키워드)하지만, 아마도 덜 알려진 (그리고 실용적인 ) 접근 방식에 대한 최신 연구이다 재귀 알고리즘의 하드웨어 구현 ( 하드웨어에 직접 "컴파일 된" VHDL 언어 사용 ). 예를 들어 V.Sklyarov의 논문 " FPGA 기반 재귀 알고리즘의 구현 "을 참조하십시오. ( 이 논문은 하드웨어에서 재귀 알고리즘을 구현하는 새로운 방법을 제안합니다. .... 데이터 정렬 및 압축 영역에서 재귀 알고리즘의 두 가지 실제 응용이 연구되었습니다. 자세히 .... ).


1

람다를 지원하는 언어에 익숙하다면 CPS 변환을 살펴볼 수 있습니다. 호출 스택 (특히 재귀) 사용을 제거하는 것은 CPS 변환이 수행하는 작업과 정확히 일치합니다. 프로 시저 호출을 포함하는 프로그램을 테일 호출 만있는 프로그램으로 변환합니다 (이것은 반복 구조 인 gotos라고 생각할 수 있습니다).

CPS 변환은 기존 스택 기반 스택에서 호출 스택을 명시 적으로 유지하는 것과 밀접한 관련이 있지만 배열 대신 호출 스택은 연결된 클로저로 표시됩니다.


0

제 생각에이 질문은 계산의 정의의 기원으로 거슬러 올라가며 오래 전에 교회가 그 당시에 엄밀하게 입증되었습니다 람다 미적분학 (재귀의 개념을 크게 포착 한)이 튜링 기계와 동등한 것으로 나타 났고 여전히 사용되는 용어 "재귀 언어 / 기능". 또한 이러한 라인을 따라 나중에 핵심 참조는 다음과 같습니다

Peter Landin의 1965 년 논문 ALGOL 60과 Church 's Lambda 표기법 사이의 대응에 의해 지적 된 바와 같이, 순차적 절차 적 프로그래밍 언어는 람다 미적분학으로 이해 될 수 있으며, 이는 절차 적 추상화 및 절차 (서브 프로그램) 적용을위한 기본 메커니즘을 제공합니다.

이에 BKD의 대부분이 위키 피 디아 페이지에있는 교회 튜링의 논문 있습니다. 정확한 내용은 확실하지 않지만 wikipedia 기사는 람다 미적분학과 튜링 머신 간의이 동등성을 최초로 입증 한 사람이 Rosser (1939)임을 나타냅니다. 아마도 / 아마도 그의 논문에는 (재귀 적 인) 람다 호출을 tm 구성으로 변환하는 스택과 같은 메커니즘이 있습니까?

JB Rosser (1939). "고델의 정리와 교회 정리의 증거에 대한 비공식 설명". 상징 논리 저널 (The Journal of Symbolic Logic, Vol. 4, No. 2) 4 (2) : 53–60. doi : 10.2307 / 2269059. JSTOR 2269059.

물론 현대 리스프 언어 와 변형 체계 는 원칙적으로 람다 미적분과 강한 유사성을 가지고 있습니다. 표현 평가를위한 인터프리터 코드를 연구하면 람다 미적분학 튜링 완전성에 대한 논문에 원래 포함 된 아이디어로 이어집니다.


1
튜링 / 람다 등가 증명이 논문의 부록에 있습니다 www.cs.virginia.edu/~robins/Turing_Paper_1936.pdf
라두 고르
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.