2014-05-20 3 views
2

++을 사용하지 않고 하스 켈에서 왼쪽에서 오른쪽으로 목록을 작성하는 방법이 있습니까?하스켈없이 왼쪽에서 오른쪽으로 목록 작성 ++

cons은 일정 시간 작업이며 코드를 효율적으로 유지하려고합니다. 이런 식으로 하스켈의 게으름을 이용하는 일반적인 방법이있는 것처럼 느껴지지만, 나는 그것을 생각할 수 없다.

은 지금 나는 Collatz 시퀀스를 생성하는 기능을 쓰고 있어요,하지만 잘못된 방향으로 목록을 구축하는 것 : GHCi에서

module CollatzSequence where 

collatz :: (Integral a) => a -> [a] -> [a]; 
collatz n l 
    | n <= 0 = error "Enter a starting number > 0" 
collatz n [] = collatz n [n] 
collatz n [email protected](x:_) 
    | x == 1 = l 
    | even x = collatz n ((div x 2):l) 
    | otherwise = collatz n ((x*3 + 1):l) 

:

*CollatzSequence> collatz 13 [] 
[1,2,4,8,16,5,10,20,40,13] 
+1

나는 우연히도, [관련없는 질문의 예]로 Collatz 시퀀스를 구현했습니다 (http://stackoverflow.com/a/23767928/791604). 아마도 트릭을 얻으려면 너지가 충분할 것입니다! (즉, 누적기를 떨어 뜨리면 ... 물건을 돌려 주기만하면됩니다.) –

답변

10

참으로 게으름을 이용하는 방법이 있습니다. 하스켈에서는 내부에 지연 데이터 생성자를 재귀 호출 할 수 있으며 스택 오버플로 또는 분기가 발생할 위험이 없습니다.

collatz :: Integer -> [Integer] 
collatz n | n <= 1 = [] 
collatz n = n : collatz next where 
    next = if even n then div n 2 else n * 3 + 1 

예를 들어, 식 head $ collatz 10head (10 : <thunk>) 평가 : 어큐뮬레이터의 필요성, 또한 그것들이 계산 순서에 해당 할 것이다리스트 내의 요소의 순서는 생성자 내부 재귀 호출을 제거 걸기 10으로 평가되며 꼬리의 썽크는 평가되지 않습니다. 또 다른 장점은 목록 노드가 목록을 반복하는 동안 가비지 수집 될 수 있다는 것입니다. foldl' (+) 0 (collatz n)은 방문한 노드가 나머지 프로그램에서 더 이상 참조되지 않고 해제 될 수 있기 때문에 일정한 공간에서 실행됩니다. 꼬리 재귀 적이기 때문에 원래 함수에서는 그렇지 않습니다. 전체 목록을 계산할 때까지는 부분 결과를 제공 할 수 없습니다.

+2

첫 번째 단락은 종처럼 명확합니다. 다음 번에 하스켈에서 꼬리 재귀에 대해 이야기 할 때 그 설명을 사용할 것입니다. 좋은 대답. – AndrewC

4

당신은이 무엇인가 찾고있어?

collatz :: (Integral a) => a -> [a] 
collatz n 
    | n <= 0 = error "Enter a starting number > 0" 
    | n == 1 = [1] 
    | even n = n : collatz (div n 2) 
    | otherwise = n : collatz (n*3 + 1) 
관련 문제