2014-12-31 1 views
9

year.hs :왜 스택 오버플로에서 year = year + 1이 실패하지 않습니까?

이 꼬리 재귀 호출하지
year = year + 1 

main = print year 

:

year = year + 1 
year = (year + 1) + 1 
year = ((year + 1) + 1) + 1 
... 

그러나 runhaskell year.hs 그것이 무한 루프로 실행을 나타냅니다 아무것도 출력하지를 않습니다.

하스켈 컴파일러가 비 꼬리 재귀 호출에도 최적화를 수행합니까?

+2

메모리 사용량을 확인하십시오. 그것은 최적화에 달려 있지만, 그것은 일어날 수있는 한 가지입니다. – luqui

+0

출력은 무엇입니까? –

+0

이 결과는 정의되지 않았다고 가정합니다. –

답변

18

게으름 때문에 (단동 제한 +1 & dagger;). 기본적으로 당신이

year = year + 1 

말을하고 year을 평가할 때, 하스켈 결과 공간을 절약하고 year을보고 다음 때 동일한 결과를 다시 사용하려고합니다. 따라서 year + 1year을 평가하려고하면 year의 코드는 실제로 입력되지 않습니다.

GHC에서 멀티 스레딩을 구현하려면 & ddagger;, 실제로 수행되는 것은 이미 평가되고있는 변수의 값을 얻으려고 할 때 현재 스레드를 차단하는 것입니다. 그런 다음 평가가 끝나면 차단 된 스레드의 실행을 다시 시작합니다. 이 경우 스레드는 자체적으로 수행중인 평가에서 차단되므로 교착 상태가 발생합니다.

대신

year() = year() + 1 

다음 날 위해 스택 오버 플로우를 제공 않습니다 year()를 실행 말한다면.


; 당신이 스택 오버 플로우를 산출, 컴파일러가 () 매개 변수와 같은 Num a 사전 치료를 완벽하게 무료 타입 서명을

year :: Num a => a 
year = year + 1 

을 추가하는 경우 때문에 단사 사상 제한이 놀이에 온다. 이 경우 실제로 문제는 아니지만 중간 결과 캐싱은 실제 계산에서 큰 문제입니다. GHC 실제로 더 또한 스택 오버 플로우를 생성하지 않습니다

year() = let y = y + 1 in y 

같은 생산, 사전에 걸쳐 내부 코드 추상화를 재귀 을 가하고있는 것처럼이 경우, 그것은 보인다.


& ddagger; 단일 스레드 모드 (GHC)와 코드 컴파일 GHC는 무한 루프를 검출하고 불평 결정 수단

<<loop>> 

을 산출한다.

+0

설명을 위해 :''연도''의 형식은 기본적으로''Int''입니까? 아니면 제가 잘못 생각합니까? – ThreeFx

+0

@ThreeFx가 적당하다고 들리지만 지금은 확인할 수 없습니다. 하지만 year 'int 형,'year :: Integer' 형,'year :: Float' 형 등 모든 형태의 타입 서명을'year '에 부여 할 수 있기 때문에 중요하지 않습니다. (해당 형식의'+ '가 엄격한 한) 동작을 변경하지 않고 형식에 Num 인스턴스가 있습니다. –

+1

@ThreeFx 전체 숫자 및 10 진수 리터럴의 기본값을 변경할 수 있지만 기본 기본값은 (Integer, Double). – AndrewC