-
Notifications
You must be signed in to change notification settings - Fork 1
3. Dipping Your toes in the pool
- 사전적 의미: 진실성 부여(사실과는 상관없이 사람들이 진실이기를 바라는 마음에서 부여하는 진실성)
-
Every object is “true” all the time, unless it’s nil or false.
(if true :truthy :falsey) ;=> :truthy (if [] :truthy :falsey) ;=> :truthy (if nil :truthy :falsey) ;=> :falsey (if false :truthy :falsey) ;=> :falsey
-
NEVER do this
(def evil-false (Boolean. "false")) evil-false ;=> false (= false evil-false) ;=> true (if evil-false :truthy :falsey) ;=> :truthy
-
right way
(if (Boolean/valueOf "false") :truthy :falsey) ;=> :falsey
-
Rarely do you need to differentiate between the two non-truthy values, but if you do, you can use nil? and false?
(when (nil? nil) "Actually nil, not false") ;=> "Actually nil, not false"
-
Keeping in mind the basic rule that everything in Clojure is truthy unless it’s false or nil is an astonishingly powerful concept, allowing for elegant solutions.
-
The seq function returns a sequence view of a collection, or nil if the collection is empty.
(seq [1 2 3]) ;=> (1 2 3) (seq []) ;=> nil
-
print-seq function
(defn print-seq [s] (when (seq s) B Check for empty (prn (first s)) (recur (rest s)))) (print-seq []) ;=> nil (print-seq [1 2]) ;1 ;2 ;=> nil
많은 객체 지향 언어에서, 너는 아마 너의 앱 데이타 객체를 관리하기 위해,각각의 게터세터 메소드의 집합과 함께 새 클래스를 만들었을 것이다. 클로저는 대신에 지어놨다 편리하게 맵과 벡터를 사용할수 있게 추상화를 하는데에. 이거는 디스트럭처링을 자연스럽고 직관적이게 한다. 너가
Clojure REPL을 사용하면 처음 사용해보는 라이브러리도 즐거운 마음으로 확인해볼 수 있다.
-
화면에 픽셀을 표현하는 x, y 좌표를 가지는 시퀀스와 xor 연산을 해서 재미난 이미지를 만들어 보자
-
먼저 range 라는 함수를 가지고 좌표를 표현해보기 위해 range가 어떻게 동작하는지 확인해본다.
(range 5) ;=> (0 1 2 3 4)
-
x, y 좌표 쌍을 만들기 위해서 for를 사용해서 원하는 결과가 나오는지 실험해보자.
(for [x (range 2) y (range 2)] [x y]) ;=> ([0 0] [0 1] [1 0] [1 1])
-
xor 연산을 위해서 xor 함수같은 것이 있을 것으로 예상하고 REPL로 실험해보자.
(xor 1 2) ;=> java.lang.Exception: Unable to resolve symbol: xor in this context
-
xor라는 이름의 함수는 없다는 것을 알았다. 같은 기능을 하는 함수가 없는지 find-doc으로 찾아본다.
(find-doc "xor") ; ------------------------- ; clojure.core/bit-xor ; ([x y]) ([x y & more]) ; Bitwise exclusive or ;=> nil
-
bit-xor라는 함수가 같은 기능을 함수라는 것을 알게되었고 REPL에서 확인해보자.
(bit-xor 1 2) ;=> 3
-
이제 먼저 만들었던 x, y 쌍을 주는 for문에 xor 값을 추가해보자. REPL에서 UP키를 누르면 이전에 실행했던 구문을 불러올 수 있다.
(for [x (range 2) y (range 2)] [x y (bit-xor x y)]) ;=> ([0 0 0] [0 1 1] [1 0 1] [1 1 0])
-
잘 된것 같으니 이제까지 만들었던 것을 나중에 사용하기 쉽게 함수로 만들자.
(defn xors [max-x max-y] (for [x (range max-x) y (range max-y)] [x y (bit-xor x y)])) (xors 2 2) ;=> ([0 0 0] [0 1 1] [1 0 1] [1 1 0])
-
위의 함수를 Clojure 소스파일 확장자인 .clj로 저장해두면 좋을것 같다. 또는 ClojureScript 파일인 .cljs로 저장해두자.
-
Clojure REPL은 자바 라이브러리를 실험하기에 좋은 환경이다. java.awt의 Frame을 가지고 시작해보자.
(def frame (java.awt.Frame.)) ;=> #'user/frame
-
Frame이 생성되었는데 볼수가 없다. 왜 그런지 frame의 상태를 확인해보자.
frame ;=> #<Frame java.awt.Frame[frame0,0,22,0x0,invalid,hidden,...]>
-
뭔가 hidden이라는 것이 보이는 걸로 보아 이것을 바꿔줄 수 있는 메서드가 있을 것 같다. Frame의 모든 메서드 중에서 Vis어쩌고로 시작되는 메서드를 찾아보자.
(for [meth (.getMethods java.awt.Frame) :let [name (.getName meth)] :when (re-find #"Vis" name)] name) ;=> ("setVisible" "isVisible")
-
관련된 메서드가 두개 보인다. 두개다 REPL에서 확인해보자.
(.isVisible frame) ;=> false (.setVisible frame true) ;=> nil
-
setVisible을 했는데도 화면에 나타자지 않는다. 아까 frame의 속성을 봤을 때 크기로 보이는 값이 0,0 이였던것을 기억해보면 크기가 지정되지 않아 화면에 안보인것 같다.
(.setSize frame (java.awt.Dimension. 200 200)) ;=> nil
-
이제 화면에 나왔다. 팁으로
(javadoc frame)
을 하면 자바 문서가 브라우저 창으로 나온다. -
화면에 뭘 그리기 위해서 그래픽 컨택스트를 가져와 보자.
(def gfx (.getGraphics frame)) ;=> #'user/gfx
-
화면에 뭘 그려보자.
(.fillRect gfx 100 100 50 75)
-
화면에 검은 사각형이 나왔다. 재미있지 않는가? 이제 오랜지색 사각형을 그려보자.
(.setColor gfx (java.awt.Color. 255 128 0)) (.fillRect gfx 100 150 75 50)
-
다른 여러가지도 REPL에서 실험해볼 수 있다.
-
앞에서 만들어둔 함수를 써서 재미난 이미지를 만들어 보자.
(doseq [[x y xor] (xors 200 200)] (.setColor gfx (java.awt.Color. xor xor xor)) (.fillRect gfx x y 1 1))
-
xors 함수에서 나오는 시퀀스의 백터 항목을 x, y, xor 값에 디스트럭처링해서 색상으로 지정하고 전체 픽셀에 그려주는 예제이다.
-
패턴이 중간에 짤리는 것을 막기위해서 이미지 범위를 더 크게 설정해보자.
(doseq [[x y xor] (xors 500 500)] (.setColor gfx (java.awt.Color. xor xor xor)) (.fillRect gfx x y 1 1)) ; java.lang.IllegalArgumentException: ; Color parameter outside of expected range: Red Green Blue
-
뭔가 잘 못되었다. REPL에서는 예외가 발생했을 때 특별한 var인 *e에 예외가 저장된다. 예외 상세 내용을 보기 위해 아래와 같이 해보자.
(.printStackTrace *e) ; java.lang.IllegalArgumentException: Color parameter outside of ; expected range: Red Green Blue ; at clojure.lang.Compiler.eval(Compiler.java:4639) ; at clojure.core$eval__5182.invoke(core.clj:1966) ; at clojure.main$repl__7283$read_eval_print__7295.invoke(main.clj:180) ; ...skipping a bit here... ; Caused by: java.lang.IllegalArgumentException: Color parameter ; outside of expected range: Red Green Blue ; at java.awt.Color.testColorValueRange(Color.java:298) ; at java.awt.Color.<init>(Color.java:382) ; ...skipping a bit more... ; ... 11 more ;=> nil
-
뭔가 긴글이 나왔다고 당황하지 말고 천천히 살펴보자. 뭔저 caused를 기준으로 크게 두 부분으로 볼 수 있고 두번째 부분인 Caused 다음에 나오는 문장 부터 보자.
at java.awt.Color.testColorValueRange(Color.java:298)
-
java의 stack trace는 아래와 같이 구성된다.
at <class>.<method or constructor>(<filename>:<line>)
-
이 경우에는
testColorValueRange
함수에서 에러가 발생했고 다음 라인을 보면Color
의 생성자에서 에러가 난것을 확인 할 수 있다. 뭔가 값을 초기화할 때 잘 못된것 같다. 이것을 고쳐보자.(defn xors [xs ys] (for [x (range xs) y (range ys)] [x y (rem (bit-xor x y) 256)]))
-
bit-xor
의 결과를 그대로 사용하지 않고 256의 나머지 값으로 바꿧다. -
다시 확인해보기 위해서 기존의 이미지를 지우는 함수를 하나 만들자.
(defn clear [g] (.clearRect g 0 0 200 200))
-
bit-xor
함수를 사용해서 재미있는 이미지를 만들어봤는데 다른 연산자를 사용해보면 또 다른 이미지를 얻을 수 있다. 그래서 아래와 같이 연산자를 파라미터로 받을 수 있는 함수를 만들어 보자.(defn f-values [f xs ys] (for [x (range xs) y (range ys)] [x y (rem (f x y) 256)])) (defn draw-values [f xs ys] (clear gfx) (.setSize frame (java.awt.Dimension. xs ys)) (doseq [[x y v] (f-values f xs ys)] (.setColor gfx (java.awt.Color. v v v)) (.fillRect gfx x y 1 1))) (draw-values bit-and 256 256) (draw-values + 256 256) (draw-values * 256 256) ``
-
REPL을 가지고 Clojure를 개발하면 사용하려는 함수를 미리 실험해봄으로 개발 시간을 더 줄 일 수 있다.