Y 조합기 및 테일 콜 최적화


20

F #에서 Y 결합기의 정의는 다음과 같습니다.

let rec y f x = f (y f) x

f는 재귀적인 하위 문제에 대한 지속성을 첫 번째 논증으로 기대합니다. yf를 연속으로 사용하면 개발할 수있는 f가 연속 호출에 적용됩니다.

let y f x = f (y f) x = f (f (y f)) x = f (f (f (y f))) x etc...

문제는, 우선,이 체계는 어떤 테일 콜 최적화의 사용을 배제한다는 것입니다 : 실제로, f에 보류중인 일부 작업이있을 수 있으며,이 경우에는 f와 관련된 로컬 스택 프레임을 변경할 수 없습니다.

그래서 :

  • 한쪽 끝에서 Y 결합기를 사용 하려면 함수 자체와 명시 적으로 다른 연속이 필요 합니다.
  • TCO를 적용하기 위해, f에서 보류중인 작업이없고 f 자체 만 호출하려고합니다.

그 두 사람이 화해 할 수있는 방법을 알고 있습니까? 어큐뮬레이터 트릭이있는 Y 또는 CPS 트릭이있는 Y처럼? 아니면 할 수있는 방법이 없다는 것을 증명하는 주장?


y 구현에 rec 키 워크를 추가 했습니까? 나는 내 독서에서 필요하다고 생각한다 ..
지미 호파에게

테일 콜을 최적화하지 못한다는 증거가 있습니까? 나는 당신이 그 함수에 대한 IL을 읽고 싶을지도 모른다고 생각해야한다. 컴파일러가 무언가를 생각 해낼만큼 똑똑하다면 놀라지 않을 것이다.
Jimmy Hoffa

연속적으로 묶이지 않은 재귀의 경우에는 그렇지 않습니다. 그러나 스택 프레임이 y 호출을 통해 재사용된다는 사실에 따라 그러한 것을 허용하도록 다시 작성할 수 있습니다 . 예, IL을보아야 할 수도 있습니다.
nicolas

5
나는 여기에 의견을 남기기 위해 계정을 만들고 50 점을 얻었습니다. 이 질문은 정말 흥미 롭습니다. 나는 그것이 전적으로 달려 있다고 생각합니다 f. 우리는 thunk로 ytailcall 할 수 있지만 보류중인 작업이있을 수 있습니다. 테일 콜 친화적 인 별도의 콤비 네이터가 있는지 아는 것이 흥미로울 것 같습니다. 이 질문이 CS Stackexchange 사이트에서 더 나은 관심을 끌지 궁금합니다. f(y f)f
John Cartwright

답변:


4

그 두 사람이 화해 할 수있는 방법을 알고 있습니까?

아니, 그리고 정당한 이유가있는 IMHO.

Y- 콤비 네이터는 이론적 인 구조이며 람다 미적분학 튜링을 완료하는 데만 필요합니다 (람다 미적분학에는 루프가 없으며 람다는 재귀에 사용할 수있는 이름이 없음).

따라서 Y 콤비 네이터는 정말 매력적입니다.

그러나 : 아무도 실제로 사용하지 않고 실제 재귀의 Y-콤비를! (재미있는 경우를 제외하고는 실제로 작동한다는 것을 보여주기 위해)

테일 콜 최적화, OTOH는 이름에서 알 수 있듯이 최적화입니다. 언어의 확장성에 아무 것도 추가하지 않습니다. 스택 공간 및 우리가 관심을 갖는 재귀 코드의 성능과 같은 실질적인 고려 때문입니다.

베타 질문에 대한 하드웨어 지원이 있습니까? (베타 축소는 람다식이 줄어드는 방법입니다.) 함수형 언어는 (내가 아는 한) 런타임에 베타 삭감 될 람다 식의 표현으로 소스 코드를 컴파일하지 않습니다.


2
Y- 콤비 네이터는 매번 사용 후에도 계속 묶이지 않는 매듭을 바꾸는 것과 같습니다. 대부분의 시스템은 이것을 단축하고 매듭을 메타 수준에서 묶어 폐기 할 필요가 없도록합니다.
Dan D.

1
마지막 단락과 관련하여 Haskell을 중심으로 그래프 축소 를 사용 하여 게으른 평가를 수행하십시오. 그러나 내가 가장 좋아하는 것은 교회-로스 격자의 경로를 항상 정상적인 형태로 최소한으로 줄이는 경로를 취하는 최적의 축소 입니다. 이러한에 나타나는 Asperti와 Guerrini의 기능 프로그래밍 언어의 최적 구현 . BOHM 1.1 참조 .
Dan D.

@DanD. 링크에 감사드립니다. 나중에 포스트 스크립트 인식 브라우저에서 시도해 보겠습니다. 물론 배울 것이 있습니다. 그러나 컴파일 된 haskell이 그래프 축소를 수행 한다고 확신 합니까? 나는 이것을 의심한다.
Ingo

1
실제로는 그래프 축소를 사용합니다. "GHC는 스파인리스 태그리스 G- 머신 (STG)으로 컴파일합니다. 이것은 명목상 그래프 축소 머신입니다 (즉, 위에서 설명한대로 그래프 축소를 수행하는 가상 머신입니다"). 에서 ... STG 기계에 대한 자세한 내용은 참조 사이먼 페이튼 존스의 척추 태그가 필요 없음 G-기계 : 재고 하드웨어에 구현 게으른 함수형 언어를 .
Dan D.

@DanD. 같은 기사에서 GHC는 "GCC를 사용하여 C를 통해 최종적으로 실제 기계 코드로 컴파일하기 전에 GHC가 해당 표현에 대해 여러 가지 최적화를 수행함"을 자세히 읽습니다.
Ingo

0

나는이 대답에 대해 완전히 확신하지 못하지만, 내가 생각해 낼 수있는 최선입니다.

y 조합기는 본질적으로 게으 르며, 엄격한 언어에서는 게으름을 수동으로 추가 람다를 통해 추가해야합니다.

let rec y f x = f (y f) x

정의를 마치려면 게으름이 필요하거나 (y f)인수가 평가를 마치지 않고 f사용 여부를 평가해야 합니다. 게으른 맥락에서 TOC는 더 복잡하며, 그 결과는 (y f)로 적용하지 않고 함수 구성을 반복합니다 x. n이 재귀의 깊이 인 O (n) 메모리가 필요하다는 것을 확신하지 못하지만 (실제로 알지 못하기 때문에 Haskell로 전환)와 같은 유형의 TOC를 얻을 수 있을지 의심됩니다. 에프#)

length acc []    = acc
length acc (a:b) = length (acc+1) b 

당신이 이미 그것을 모른다면, Haskell foldl과 의 차이점 foldl'이 상황에 약간의 빛을 발할 수 있습니다. foldl간절한 언어로 작성되었습니다. 그러나 TOC를 수행하는 대신 foldr, 어큐뮬레이터는 부분적으로 평가할 수없는 잠재적으로 엄청난 썽크를 저장하기 때문에 실제로 더 나쁩니다 . (이것은 foldl과 foldl '이 무한리스트에서 작동하지 않는 이유와 관련이 있습니다.) 따라서 더 최신 버전의 Haskell foldl'이 추가되었습니다.이 기능은 함수가 반복 될 때마다 누산기가 평가되지 않도록하기 위해 누산기를 평가합니다. 나는 http://www.haskell.org/haskellwiki/Foldr_Foldl_Foldl%27 이 이것을 나보다 더 잘 설명 할 수 있다고 확신한다 .

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.