2015년 9월 7일 월요일

Living Clojure -- Week 3, Day 1

3주차만 하면 4Cloure 문제풀이는 끝난다. Code Golf 하는 재미가 있었는데, 벌써 아쉬움이 ..

Living Clojure에서 제시하는 이번주 주요 토픽은...

  • Control flow
  • Recursion
  • Data transformation

자, 3주차 1일째 시작!



(= (__ '(:a (:b nil nil) nil))
   true)
(= (__ '(:a (:b nil nil)))
   false)

시퀀스가 이진트리인지 확인하는 함수를 작성하는 문제. 각 노드는 nil이거나 양쪽 자식이 모두 있어야 한다.

위의 예는 :a 루트에 왼쪽 자식만 :b 가 있는 경우를 제대로 표현한 것과 그렇지 않은 것을 보여준다. 즉, root 뒤에 딱 두개의 요소만 있는지 확인하는 문제다.


(fn f[s]
  (if (nil? s) true
    (let [[root left right & more] (seq s)]
      (if (empty? more) (and (f left) (f right))
        false))))


틀린답. 두번째 if에서 sequence가 3개를 넘는지만 체크하므로 틀린 답이다. sequence에서 두번째/세번째 요소를 가져오는 방법을 binding(destructuring)으로 풀고 싶은데, 그러자면 core.match 라이브러리를 사용해야 하나보다. 

아하! if-let이 있지 않을까? 있다! https://clojuredocs.org/clojure.core/if-let

(fn f[s]
  (if (nil? s) true
    (if-let [[root left right] (seq s)]
      (and (f left) (f right))
      false)))

If-let binding 패턴이 맞지 않을 때 else 브랜치를 타겠거니 했으나 그렇게 동작하지는 않는 모양이다.

;;98
(fn f[s]
  (cond 
   (nil? s) true
   (not (sequential? s)) false
   (= 3 (count s)) (and (f (second s)) (f (nth s 2)))
   :else false))

두번째 sequential? 체크를 빼먹어서 틀렸다가 바로잡았다. 타입을 런타임 체크로 따져줘야 한다는 점이 매우 번거롭다.

;; 72
(fn f[s]
  (or 
   (nil? s)
   (and (sequential? s) (= 3 (count s)) (f (second s)) (f (nth s 2)))))




(= (__ '(:a (:b nil nil) (:b nil nil))) true)
(= (__ '(:a (:b nil nil) nil)) false)

이진트리에서 좌우가 대칭인지 판별하는 함수를 작성하는 문제.
tree-seq로 sequence를 만들어 reverse와 같은지 볼 수 있지 않을까? 하지만 tree-seq는 부모먼저 자식 나중이다. 만약 sequence로 만들어서 풀고 싶다면 in order 로 sequence를 만들어야 한다.

(fn [t]
  (let [in-order (fn f[t] (if (nil? t) [] (concat (f (second t)) (vector (first t)) (f (nth t 2)))))
        s1 (in-order t)
        s2 (reverse s1)]
    (= s1 s2)))


in-order 로컬함수를 만들어서 구현해봤다.

;; 97
(fn [r]
  (let [i (fn f[t] (if (nil? t) [] (concat (f (second t)) [(first t)] (f (nth t 2)))))
        s (i r)
        t (reverse s)]
    (= s t)))

혹은 전체를 mirror해서 같은지 비교할 수도 있지 않을까?

;; 59
#(= % ((fn m[t]
         (if (nil? t) nil
           [(nth t 0) (m (nth t 2)) (m (nth t 1))])) %))

nil? 체크를 C처럼 쓸수 있는 건 다행인지 불행인지 -.-;

;; 50
#(= % ((fn m[t]
         (if t
           [(nth t 0) (m (nth t 2)) (m (nth t 1))])) %))


nth를 desctructuring으로 바꿀 수 있다. (if-let/when-let)

;; 43
#(= % ((fn m[t]
         (if-let [[t l r] t]
           [t (m r) (m l)])) %))


댓글 없음:

댓글 쓰기