2017년 1월 22일 일요일

[clojure]nil 체크

nil 과 false를 제외한 모든 것이 반복문이나 조건문에서 true가 된다.

user=> (if nil true false)
false
user=> (if false true false)
false
user=> (if -1 true false)
true
user=> (if 0 true false)
true
user=> (if "false" true false)
true
하지만 비어있는 컬렉션컬렉션은?
user=> (if [] true false)
true
이럴수가. 하지만 이렇게 하면 된다.
user=> (if (not (empty? [])) true false)
false
이게 뭔고생인가. Joy Of Clojure에서는 다른 방법을 제시한다. 바로 (seq s)이다.
user=> (defn print-seq [s]
  #_=>   (when (seq s)
  #_=>     (prn (first s))
  #_=>     (recur (rest s))))
#'user/print-seq
user=> (print-seq [])
nil

여기서는 rest를 쓰고 next를 쓰지 말라고 하는데 왜인지 한번 보자.
user=> (defn my-seq [s]
  #_=>   (when (seq s)
  #_=>     (prn (first s))
  #_=>     (recur (next s))))
#'user/my-seq
user=> (my-seq [])
nil

음... 이게 문제는 아닌 것같다.
user=> (next [])
nil
user=> (rest [])
()
이게 문제인 것 같다.
rest는 시퀀스가 비어있는지 아니던지 nil를 리턴하지는 않는다.
next는 바로 nil을 리턴한다.
우리는 각 반복 시점마다 (seq s)를 쓴다 그러니 시퀀스를 다루는 rest를 넣는게 더 조합이 잘되있다고 보는 것이다. (nil이 나오지 않게 하려 하는 점은 좋은 생각이다.)

** 여담으로 컬렉션을 순회할 때는 재귀보다는 doseq를 사용하는 편이낫다고 한다. 다만 doseq를 사용하면 위철머 살펴 보는 것은 힘들다. 클로저에서 do로 시작하는 구문 (doseq, dotimes, do 등)은 부수 효과를 일으키기 위해 사용하기 때문에 보통 결과로 nil을 리턴한다.

댓글 없음 :

댓글 쓰기