2013-12-18 4 views
1

이 코드 블록을 고려하십시오.함수를 두 번 호출하는 것을 피하는 방법

(loop [k from res '()] 
    (if (< (count res) n) 
     (recur (next-num k) (conj res (next-num k))) 
     (sort res))) 

이제는 함수 (next-num k)이 값 비싼 계산을한다고 가정합니다. 우리는 그 두 번 전화 할 여유가 없습니다. 대안은 무엇입니까? Clojure를 처음 접했고 많은 기본 기능을 알지 못합니다. 그러나 나는 방법이 있어야한다고 확신합니다.

답변

5

사용 let는 : 그러나

(loop [k from res '()] 
    (if (< (count res) n) 
    (let [next-k (next-num k)] 
     (recur next-k (conj res next-k))) 
    (sort res))) 

loop에 도달하기 전에, 당신이 코어를 구성 할 수 있는지 보는 가치 :

(loop [k from res '()] 
    (if (< (count res) n) 
     (let [the-next-num (next-num k)] 
      (recur the-next-num (conj res the-next-num))) 
     (sort res))) 
+4

또는 전체 루프를 피하기'(- >> (에서 다음-NUM을 반복) 나머지 (N을) 종류)' – Beyamor

+0

@Beyamor : 귀하의 제안 매력처럼 작동한다. 그러나 나는 이유를 모른다. 좀 더 자세히 설명해 주시겠습니까? 아마 당신의 대답과는 별도로 대답 해주십시오. –

+0

고마워, 네이선. 그건 속임수 야. –

5

@NathanDavis 말했듯이, let는 중간 값 이름을 지정할 수 있습니다 기능이 동일한 효과를냅니다. 종종 덜 복잡한 것을 작성하고 중요한 세부 사항을 폭로 할 수 있습니다.

코드의 내용은 next-num의 반복되는 응용 프로그램을 만드는 데 관련이 있습니다. 다행히도이 작업을 수행하는 핵심 기능이 있습니다 : iterate.

(iterate next-num from) 
; => (from, from', from'', ...) 

그러나, 우리는이 값의 첫 번째 원하지 않는다 : iterate 사용하여, 우리는 값의 무한 게으른 시퀀스를 생성 할 수 있습니다. 우리는 이러한 n 값을 정렬 할 수 있습니다, 마지막으로

(take n 
    (rest 
    (iterate next-num from))) 
; => (from', from'', from''') 

과 : 우리가 taken 값을 잡을 수 있습니다,이 시점에서

(rest 
    (iterate next-num from)) 
; => (from', from'', from''', ...) 

: 우리가 잘와 시퀀스의 나머지 rest를 얻을 수 있습니다 :

(sort 
    (take n 
    (rest 
     (iterate next-num from)))) 
; => (from'', from', from''') 

물론 중첩 기능 호출은 곧 어색해집니다. 스레딩 매크로 ->> (그 형제 ->처럼) 우리가 무언가로 조금 더 좋은 우리의 코드를 재 배열 할 수 있습니다 문법 설탕 약간이다 : 그래서

(->> 
    (iterate next-num from) 
    rest 
    (take n) 
    sort) 

는 시퀀스 조작 기능의 강력한 라이브러리가 있습니다 방법, 당신이 볼 수 우리는 저레벨 루핑에서 벗어납니다.

+1

정말 멋진 설명입니다. 나는 다른 질문을 받아 들였다. 왜냐하면 실제로 대답은 내 질문의 대답이기 때문이다. 그러나이 접근법은 명확하고 명확하게 더 좋습니다. –

관련 문제