2012-03-15 3 views
2

나는 꼬리 재귀 함수임을 알고있다. 그러나 내가 정의한 방식 때문에 컴파일러는 비 꼬리 자리에서 재귀 호출이있는 함수에 대해 불평합니다. 이것은 함수입니다.이 꼬리 재귀 스칼라 함수에 주석을 달 수있는 방법

@tailrec 
def travel: (Int, List[Char]) => Int = { 
    case (n,  Nil) => n 
    case (n, '~' :: sls) => travel(0, sls) 
    case (n, '^' :: sls) => travel(max(n-1,0), sls) 
    case (n, '>' :: sls) => travel(n+1, sls) 
    case (_, s :: sls) => throw new IllegalArgumentException("Illegal selector '" + s + "'") 
} 

나는

error: could not optimize @tailrec annotated method travel: it contains a recursive call not in tail position 
def travel: (Int, List[Char]) => Int = { 

나는이로 작성하는 경우, 그것은 잘 작동을 얻을.

@tailrec 
def travel(n:Int, l:List[Char]): Int = (n,l) match { 
    case (n,  Nil) => n 
    case (n, '~' :: sls) => travel(0, sls) 
    case (n, '^' :: sls) => travel(max(n-1,0), sls) 
    case (n, '>' :: sls) => travel(n+1, sls) 
    case (_, s :: sls) => throw new IllegalArgumentException("Illegal selector '" + s + "'") 
} 

나는 def: (Input) => Output = {} 형식 선언 스타일과 관련이 있다고 생각합니다. 그것은 중첩 된 일치 또는 튜플에 일치하는 것을 작성하는 것보다 더 깨끗하게 보입니다.

+0

전체 질문을 다음과 같이 다시 포맷 할 수 있다고 생각합니다. "익명 함수에'@ tailrec' 주석을 추가 할 수 있습니까? * – paradigmatic

+0

@paradigmatic - 다른 질문이지만 좋은 답변입니다. 주석이 아니지만 익명 함수가 꼬리 재귀 호출을 수행하는 방법입니다. (자신의'apply' 메소드를 볼 수 없습니다.) –

답변

7

둘은 동일하지 않습니다. 첫 번째 경우 메서드 은 함수을 생성 한 다음 메서드를 다시 호출합니다 (함수를 생성하는 등). 즉, 첫 번째 경우에 travel으로 전화 할 때마다 Function1[(Int, List[Char]), Int]의 새 인스턴스를 생성합니다. 당연히이 점프 명령을 점프 명령으로 변환 할 수는 없습니다. (이론적으로는 분석 할 수 있지만 모든 객체 생성을 취소해야하므로 분석이 복잡 할 것입니다.) 두 번째 경우에는 자체를 호출하는 메소드 일 뿐이며이 메소드는 도약.