목록의 길이를 계산하기위한 꼬리 최적화 기능에 가장 적합한 접근법은 무엇입니까?

StackOverflow https://stackoverflow.com/questions/473967

  •  19-08-2019
  •  | 
  •  

문제

다음은 포럼 포스터가 제공 한 예입니다.이 꼬리가 최적화되었는지 알 수 없습니다. 또한 누군가가 테일 최적화 버전이 일반 버전을 어떻게 우선하는지에 대한 Laymans를 설명 할 수 있습니다.

(defun mylength (s)
  (labels ((mylength-inner (s x)
            (if (car s) (mylength-inner (cdr s) (+ x 1)) x)))
          (mylength-inner s 0)))

비 꼬리 최적화 버전?

(defun l (s) (if (car s) (+ 1 (l (rest s))) 0))
도움이 되었습니까?

해결책

함수는 직접 호출을 반환하거나 그 자체로 전화를 걸지 않으면 꼬리를 최적화 할 수 있습니다. mylength-inner 함수도 반환됩니다 x 또는 (mylength-inner (cdr s) (+ x 1)), 따라서 꼬리 최적화 될 수 있습니다.

이것은 컴파일러가 함수를 재귀 적으로 호출하는 대신 루프로 전환 할 수 있음을 의미합니다. x를 반환하거나 (cdr s)를 s, s로 할당하고 x를 증가시키고 상단에서 다시 시작하십시오. (이 체계 표준은 구현 이이 최적화를 수행 할 수 있어야하지만 공통 LISP 표준은이를 구현에 이끌어냅니다. 물론,이 최적화는 매우 유용한 일이므로 대부분의 구현은이를 수행합니다.)

최적화되지 않은 버전에서 L은 전화를 L로 반환하는 것이 아니라 L이 추가 된 L에 대한 전화의 결과를 반환합니다. 즉, 직접 루프로 바꿀 수 없으므로 모든 기능 호출을 만들어야합니다.

컴파일러가 L을 루프로 바꾸고 싶다고 가정합니다. (REST S)의 할당에는 문제가 없지만 어디에 두는가 (1 + ...)?

다른 팁

FWIW, CL은 테일 호출을 최적화 할 것이라고 보장하지 않습니다. 구현에 따라 다릅니다. SBCL이 지원합니다. 이는 스키마와 다르며, 사양은 컴파일러가 꼬리 호출을 제거해야합니다. 당신이 그것을하지 않으면, 당신은 계획이 아닙니다.

또한, 꼬리 재귀는 Cl에서 다소 비 이동체이다. 우리는 a loop 매크로, 사용해요 :)

콜 스택에 추가 공간이 필요하지 않도록 테일 호출을 최적화 할 수 있으며, 기능의 마지막 작업은 재귀 호출이어야합니다. 비 꼬리 버전의 마지막 작업은 추가 된 것이므로 재귀 호출에는 자체 스택 프레임이 필요합니다.

이는 간단한 패턴을 따르고 외부 함수 인수 외에 축합기 인수를 취하는 내부 기능을 정의하고 갈 때 답을 축적합니다. 끝까지 도착하면 누적 된 값을 산출하십시오.

여기에는 더 나은 설명이있을 것입니다.

http://mitpress.mit.edu/sicp/full-text/book/book-zh-11.html#%_SEC_1.2.1

목록 길이의 계획의 "교과서"예제는 다음과 같습니다. http://www.scheme.com/tspl3/start.html#./start:h8 "길이"를 찾으십시오.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top