문제

나는 해결 45 문서 4clojure.com 고 반복되는 방법에 문제가 나가려고 일부 문제를 해결하기 위해 사용하는 재귀 및 축전지.

나는 설명하려고 최선을 다 내가 무슨 일을 끝나고 못생 솔루션을 희망하는 일부 Clojurers 것"얻는"내가 무슨하지 않습니다.

예를 들어,문제의 34 요청을 작성 기능(사용하지 않고 범위 수)에는 두 개의 정수를 인수로 만듭 범위(를 사용하지 않고 범위).단순히 당신이(...1 7)고 당신은(1 2 3 4 5 6).

이제 이 문제는 해결에 대해 이 특정한 문제입니다.

어떤 경우 고 싶 이를 해결하기 위해 사용하는 재귀 및 어큐뮬레이터?

내 생각 과정은 다음과 같습니다.

  • 을 작성하는 데 필요한 기능을 두 개의 인수,나는 시작 (fn[x y])

  • 용할 수 있습니다.recurse 신의 목록을 사용한다고 가정하고 설명하겠는 어큐뮬레이터,그래서를 작성 제 2 기능 안에 첫 번째 중 하나를 복용 추가 인수:

    (fn [x y]
    (fn(g[x y acc]...) x y '())

(나는 분명히할 수 없는 형식으로 Clojure 코드에도!?)

여기에서 내가 이미지하고 있어요 그것이 제대로:첫 번째 기능 을 정확히 두 개의 정수(내화)그리고 나는 확실하지 않다:하고 싶은 경우에 사용하는 어큐뮬레이터를 사용할 수 있습니는 어큐뮬레이터를 만들지 않고 중첩된 기능이?

다음하고 싶 conj, 지만,나는 할 수 없:

(conj 0 1)

그래서 나는 이상한 일을 확인하는데 시퀀스의 첫 번째 나는 다음과 같은 결과를 얻게 됩니다:

(fn
   [x y]
   ((fn g [x y acc] (if (= x y) y (conj (conj acc (g (inc x) y acc)) x)))
    x
    y
    '()))

하지만 그런 다음 이를 생산하 this:

(1 (2 (3 4)))

대신 이:

(1 2 3 4)

그래서 내가 끝까지 하기 추가 평평 그것은 작동하지만 완전히이다.

내가 이해하기 시작하는 몇 가지고 나가도 시작,일부 경우에는"생각하고"더 clojuresque 방법으로만 문제가 쓰는 솔루션입니다.

예를 들어 여기에서 내가 결정:

  • 을 사용하는 어큐뮬레이터
  • 을 재귀에 의해 증가 x 에 도달할 때까지 y

그러나 나는 끝까지 가진 괴물이다.

의 방법으로 이 문제를 해결하기하고 다시 한 번,그것은 내가 무슨다.

난 후에 어떻게 한 후,내가 결정하는 단점/conj,사용하는 어큐뮬레이터,그리고 재귀,나는 끝날 수 있는 이(에 의해 작성되지 me):

#(loop [i %1
        acc nil]
  (if (<= %2 i)
    (reverse acc)
    (recur (inc i) (cons i acc))))

대신 이:

((fn
  f
  [x y]
  (flatten
   ((fn
     g
     [x y acc]
     (if (= x y) acc (conj (conj acc (g (inc x) y acc)) x)))
    x
    y
    '())))
 1
 4)

나는 그것을의 시작을 해결할 수 있는 몇 가지 문제지만 나는 비트에 의해 실망의 추악한 솔루션을하는 경향이있다.

도움이 되었습니까?

해결책

가 있다고 생각하기 위해 몇 가지 여기에 대해 알아 봅니다.

첫째, 종류의 일반 규칙을 재귀적 함수는 일반적으로는 자연적인 순서를 추가 어큐뮬레이터는 반전니다.당신이 볼 수 있기 때문에 그 때에는"정상"( 어큐뮬레이터)재귀적 기능을 실행,그것은 몇 가지 작업을 값을 계산하는 다음 recurses 를 생성하는 꼬리 목록의,마지막으로 끝나는 빈 목록입니다.이에 반하는 어큐뮬레이터는,당신은 시작과 함께 빈 목록에 추가한 것을 전면-그것은 성장하고 에서 다른 방향으로.

그래서 일반적으로 추가할 경우에는 어큐뮬레이터는,당신을 얻을 반전 순서입니다.

이제 종종이 중요하지 않습니다.예를 들어,만약 당신이 생성되지 않 하는 값을 반복되는 응용 프로그램의 commutative 운전자(또한 같거나 곱하기).당신은 동일한 응답을 얻고 있습니다.

그러나 당신의 경우,그것은 문제입니다.당신 목록을 얻을 뒤:

(defn my-range-0 [lo hi] ; normal recursive solution
  (if (= lo hi)
    nil
    (cons lo (my-range-0 (inc lo) hi))))

(deftest test-my-range-1
  (is (= '(0 1 2) (my-range-0 0 3))))

(defn my-range-1 ; with an accumulator
  ([lo hi] (my-range-1 lo hi nil))
  ([lo hi acc]
    (if (= lo hi)
      acc
      (recur (inc lo) hi (cons lo acc)))))

(deftest test-my-range-1
  (is (= '(2 1 0) (my-range-1 0 3)))) ; oops!  backwards!

이며 최상의 해결하기 위해 수행할 수 있는 작업이 반대하는 목록의 끝에서.

하지만 여기에 거의 대안-우리는 실제로 할 수 있는 일을 거꾸로입니다.대 증가 낮은 제한할 수 있는 감소 높은 제한:

(defn my-range-2
  ([lo hi] (my-range-2 lo hi nil))
  ([lo hi acc]
    (if (= lo hi)
      acc
      (let [hi (dec hi)]
        (recur lo hi (cons hi acc))))))

(deftest test-my-range-2
  (is (= '(0 1 2) (my-range-2 0 3)))) ; back to the original order

[참고 있는 또 다른 방법으로 반전의 일을 아래;지 않았 구조로 내 주장을 매우 잘]

두 번째, 당신이 볼 수 있에 my-range-1my-range-2, 수있는 좋은 방법 작성의 기능과 함께 어큐뮬레이터는 기능으로 두 개의 서로 다른 설정의 인수를 사용합니다.제공하는 당신은 매우 깨끗하(imho)구현에 대한 필요없이 중첩된 기능이다.


또한 당신은 좀 더 많은 일반적인 질문에 대해 시퀀스 conj 과 같습니다.여기에 clojure 은 종류의 지저분이지만,또한 유용합니다.위게 주었어 매우 전통적인 관점과 단점을 기반으로 목록입니다.하지만 clojure 을 권장 당신이 사용하는 다른 시퀀스입니다.와 달리 단점 목록,벡터장,하지 않습니다.그래서 또 다른 는 방법을 반대하는 결과가 사용하는 벡터:

(defn my-range-3 ; this looks like my-range-1
  ([lo hi] (my-range-3 lo hi []))
  ([lo hi acc]
    (if (= lo hi)
      acc
      (recur (inc lo) hi (conj acc lo)))))

(deftest test-my-range-3 ; except that it works right!
  (is (= [0 1 2] (my-range-3 0 3))))

conj 가 오른쪽에 있습니다.사용하지 않았 conjmy-range-1, 다,그래서 여기에 그것은 다시 작성을 명확:

(defn my-range-4 ; my-range-1 written using conj instead of cons
  ([lo hi] (my-range-4 lo hi nil))
  ([lo hi acc]
    (if (= lo hi)
      acc
      (recur (inc lo) hi (conj acc lo)))))

(deftest test-my-range-4
  (is (= '(2 1 0) (my-range-4 0 3))))

이 코드는 보 비슷 my-range-3 그러나 결과는 뒤로하기 때문에 우리가 시작으로 빈 목록이 있는 벡터입니다.두 경우 모두에서, conj 추가로 새로운 요소는"자연적인"위치입니다.에 대한 벡터의 오른쪽으로,그러한 목록의 왼쪽에 있습니다.

고 그냥 나게 발생할 수 있는지 정말 이해 어떤 목록입니다.기본적으로 cons 만들자를 포함하는 두 개의 것(변수).첫째는 내용과 두 번째는 나머지의 목록입니다.그래서 목록 (1 2 3) 기본적으로 (cons 1 (cons 2 (cons 3 nil))).반면에,벡터 [1 2 3] 작품에 더 다음과 같 array(내가 생각하지만 그것은 사용하여 구현된 나무).

그래서 conj 조금 복잡하기 때문에 그것이 작동하는 방법에 따라 달라집니다목록을 위해,그것은 전화 cons 그 것들을 추가합니다.하지만 위한 벡터장 array(과 같은 일)오른쪽에 있습니다.또한,note conj 기존의 시퀀스로 첫 번째 arg 및 일이 추가로 두 번째는 동안, cons 반대(일을 추가 먼저).


모든 위의 코드를 사용할 수 있에 https://github.com/andrewcooke/clojure-lab


업데이트:나는 재작성 테스트를 기대한 결과 인용 된 목록을 경우에는 코드를 생성합니다. = 을 비교 목록과 벡터와 true 를 반환하는 경우 컨텐츠는 같지만 그것을 만드는 명시적 보여 더 많은 것을 명확하게 당신이 실제로 각각의 경우에.note '(0 1 2)' 앞에서 처럼 (list 0 1 2) -이 ' 지에서 평가되고 있는(그것없이, 0 것으로 처리되는 명령).

다른 팁

을 읽은 후에 모든 것,내가 여전히 확인할 필요는 어큐뮬레이터.

((fn r [a b]
    (if (<= a b) 
       (cons a (r (inc a) b)))) 
  2 4)
=> (2 3 4)

는 것처럼 예쁜 직관적 재귀적인 솔루션입니다.의 변경에서"진짜"코드를 사용하는 것으 seq 그래서 밖으로 실행되지 않습니다 스택의 큰 범위를 다룹니다.

제가 어떻게 여기까지 왔는지에 대하여는 솔루션:

생각할 때 사용하는 재귀,나는 그것을 찾는 데 도움이 시도하고 가장 적은 용어를 생각할 수 있고,손에 떨어져 많은"작업을"을 재귀 자체입니다.

특히,당신이 의심되는 경우 드롭할 수 있는 하나 이상의 인수/변수,일반적으로 이동하는 방법에 적어도 당신이 원하는 코드가 쉽게 이해하고 디버깅;때때로 당신은롭지 않는 단순함의 호의에 실행 속도나 메모리 사용량을 줄여 줍니다.

이 경우에는,내가 무엇을 생각할 때 나는 쓰기 시작했:"첫 번째 인수하는 기능도 시작 요소의 범위,그리고 마지막 인수는 마지막 요소"라고 할 것입니다.재귀의 생각은 뭔가를 당신은 종류의 자신을 훈련해야 하지만,상당히 확실한 해결책이 다음을 말한다:a 범위 [a, b] 은 시퀀스를 시작하는 요소 a 다음 a 범위[a + 1, b].그래서 범위 참으로 수술을 재귀적으로.코드를 썼다는 것은 꽤 많이 직접 구현을 하는 생각이 아니다.

부록:

내가 찾는 때 쓰는 기능 코드,축전지(및 인덱스)는 최고의 피할 수 있습니다.몇 가지 문제가 필요하지만 경우에 당신은 방법을 찾을 수 있습니다 그들을 제거하는,당신은 일반적으로 더 나은 경우에는 않습니다.

부록 2:

에 대한 재귀적 기능과 목록/시퀀스 가장 유용한 방법을 생각할 때 쓰는 코드 종류는 당신의 문제의 측면에서"첫번째 항목(머리)의 목록"과"의 나머지 부분에 목록(tail)".

추가할 수 없음을 이미 좋은 대답을 받았지만 내가 응답할 것입니다.로 Clojure 학습 과정을 찾을 수 있습니다 많은 있지만 모든 솔루션을 이용하여 해결할 수 있습 Clojure 내장 기능이 같은지도와 생각도 문제의 측면에서의 시퀀스입니다.이 의미하지 않지 않아야 합를 해결하는 것을 재귀적으로,그러나 당신이 듣게 될 것입니다-나는 그것을 믿을 수 있는 현명한 충고-그 Clojure 재귀를 해결하기 위한 매우 낮은 수준 문제를 해결할 수 없는 또 다른 방법입니다.

할 일이 많이 있습니다.csv 파일 처리,그리고 최근에 코멘트를 받는 nth 만듭 종속성입니다.그것은,그리고 사용하는지도의 수를 얻을 수 있도록에서 요소를 비교하여 이름과 위치.

나를 사용하는 코드의 n 번째로 clojure-csv 구문 분석된 데이터에 두 개의 작은 응용 프로그램에서 이미 생산입니다.그러나 내가 생각한 것들에 대해서는 더 sequency 방법은 다음에.

그것은 배우기 어려운 일이에서 도서에 대해 이야기하는 벡터와 nth,반복..되풀이하고,그리고 다음을 깨달을 학습 Clojure 성장을 기대합니다.

는 것들 중 하나 내가 찾는 것은 좋은 학습에 대한 Clojure,는 지역사회를 존중하고 도움이 됩니다.결국,그들을 돕는 사람의 첫 번째 학습 언어 Fortran IV 에 CDC 사이버와 함께 카드 펀치,그리고 그의 첫번째 상업적인 프로그래밍 언어 PL/I.

면 해결이 어큐뮬레이터를 사용하여 내가 뭔가를 다음과 같:

user=> (defn my-range [lb up c]
         (if (= lb up)
           c
           (recur (inc lb) up (conj c lb))))
#'user/my-range

그런 다음 전화

#(my-range % %2 [])

물론,난 사용 letfn 거나 뭔가 주위에 얻지 defn 유효합니다.

그래서 그렇습니다,당신은 필요한 내부 기능을 사용하여 어큐뮬레이터에 접근 방식이다.

내 생각 프로세스는 한번 나를 수행에 대답하고 싶을 것입하는 어큐뮬레이터에서.(대조하는 솔루션과 함께,당신이 할 일이 많이 찾는 끝-상태입니다.) 그래서 나는 나의 종료 상태와는 경우에 도달 했습니다 저는 어큐뮬레이터.그렇지 않으면 내가 압정에서는 다음 항목을 축적하고 재발을 위한 작은 경우입니다.그래서 거기에는 2 만 것 그 밖으로,최종 조건은,그리고 무엇을 어큐뮬레이터에서.

사용 벡터 많은 도움이기 때문에 conj 에 추가하고 있을 사용할 필요가 없 reverse.

내가 너무 4clojure, btw.바빴어요 그래서 난 뒤에 떨어진 요즘.

그것처럼 보이는 당신의 질문을 더하는 방법"에 대해 배우는"그 기술이/코드를 문제입니다.당신이 쓰는 종류의 코드기 때문에서는 어떤 방법으로 또는 원본을 배웠는 일반적으로 프로그래밍 또는 Clojure 에서 특정을 만들었다"신경 고속도로에서"당신의 두뇌는 생각에 대한 솔루션이 특정한 방법으로 당신은 끝까지 코드를 작성은 이렇습니다.기본적으로 어떤 문제에 직면하게 때마다(이 특별한 경우 재귀 및/또는 축적)당신은 사용하는"신경 고속도로"항상 올라와 그 종류의 코드입니다.

에 대한 솔루션을 제거의"신경 highway"를 중지 코드를 작성하는 순간 유지하는 키보드리고를 읽기 시작하는 많은 기존 clojure 의 코드(에서 기존의 솔루션을 4clojure 문제를 오픈 소스 프로젝트에 github)고 생각하는 그것에 대해 깊이(도 읽는 기능을 2~3 번이 정말로 그것이 정착에서 당신의 두뇌).이 방법은 당신이 끝날 것을 파괴하는 기존의"신경 highway"(을 생성하는 작성하는 코드는 지금)및니다 새로 만들고"신경도"하는 것을 생산하고 아름다운 관용 Clojure 코드입니다.또한,지 않으려고 뛰어를 입력하는 코드로 당신은 문제가,오히려 자신에게 어떤 생각하는 시간이 명확하고 깊은 문제에 대한 솔루션이 있습니다.

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