User Tools

Site Tools


lecture:4clojure:level-elementary

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

lecture:4clojure:level-elementary [2015/04/23 03:56]
psk810 [for]
lecture:4clojure:level-elementary [2019/02/04 14:26]
Line 1: Line 1:
-====== Elementary 레벨 문제풀이를 위한 Clojure 문법 ====== 
  
- 
-==== 키워드 자료형 ==== 
- 
-키워드(Keyword)는 Java의 Enum 과 같은 개념으로 생각하면 된다. 즉 임의의 상수이다. 
-:으로 시작하는 임의의 문자열은 키워드이다. 
- 
-<code clojure> 
-:a  
-:1  
-:@ 
-</​code>​ 
- 
-==== Boolean과 Equality ==== 
- 
-Clojure에서 참/​거짓을 나타내는 논리형 데이타는 true와 false 이다. 
- 
-<code clojure> 
-(= 1 1) ;==> true 
-(= 1 2) ;==> false 
- 
-(if true 1 2) ;==> 1 
-(if false 1 2) ;==> 2 
-(= true (not false)) ;==> true 
-</​code>​ 
- 
- 
-false 과 nil 이외의 모든 값은 참이다. 
- 
-<​code ​ clojure> 
-(if false 1 2) ;==> 2 
-(if nil 1 2) ;==> 2 
- 
-(if 0 1 2) ;==> 1    0은 숫자 
-(if 1 1 2) ;==> 1    1은 숫자 
-(if ""​ 1 2) ;==> 1   ""​ empty string 
-(if \A 1 2) ;==> 1   \A 는 문자(Character) 
-(if [] 1 2) ;==> 1   [] empty vector 
-</​code>​ 
- 
-==== Java Interop ==== 
- 
-Clojure는 Java 코드를 그대로 가져다 사용할 수 있는 방식을 제공하는데,​ 이것을 Java Interop이라고 한다. 
- 
-Clojure의 문자는 Java의 Character 인스턴스에,​ 스트링은 Java의 String 인스턴스이다. 
- 
-Java 오브젝트의 메소드를 다음과 같이 호출할 수 있다. 
- 
-<code clojure> 
-(.toUpperCase "​abc"​) ;==> "​ABC"​ 
-</​code>​ 
- 
-클래스의 정적 메소드는 다음과 같이 호출할 수 있다. 
- 
-<code clojure> 
-(Character/​isUpperCase \A) ;==> true 
-</​code>​ 
- 
-==== 함수 호출 ==== 
- 
-Clojure는 Lisp이기 때문에 괄호를 사용한다. 
- 
-괄호의 첫 요소는 함수이고,​ 나머지는 파라미터이다. 
- 
-<code clojure> 
-(str "Hello " "​World!"​) ;==> "Hello World!"​ 
-</​code>​ 
- 
-따라서 수치연산 함수는 전위연산자이다. 
- 
-<code clojure> 
-(+ 1 1) ; => 2 
-(- 2 1) ; => 1 
-(* 1 2) ; => 2 
-(/ 2 1) ; => 2 
- 
-(+ 1 (- 3 2)) ; = 1 + (3 - 2) => 2 
-</​code>​ 
- 
- 
-==== 익명 함수 ==== 
- 
-<code clojure> 
-(fn [s] (println "​hello,​ " s)) 
-#(println "​hello,​ " %) 
- 
-(#(* % %) 5) ;==> 25 
-((fn [n] (* n n)) 5) ;==> 25 
- 
-(#(* %1 %2) 5 4) ;==> 20 
-((fn [x y] (* x y)) 5 4) ;==> 20 
-</​code>​ 
- 
-==== 자료 구조 ==== 
- 
-Clojure에는 4개의 자료 구조가 있다 : List, Vector, Set, Map 
- 
- 
-<code clojure> 
-(1 2 3)  ; 리스트는 ()로 묶는다. 순서가 있으며 index를 통한 임의 접근이 않된다. 
-[1 2 3]  ; 벡터는 []로 묶는다. 순서가 있으며 index를 통한 임의 접근이 된다. 
-#{1 2 3} ; 집합은 #{}로 묶는다. 순서가 없으며 value를 통한 접근이 된다. value는 중복값을 가질 수 없다. 
-{:a 1 :b 2 :c 3}  ; 맵은 {}로 묶는다. 순서가 없으며 key를 통한 접근이 된다. key는 중복값을 가질 수 없다. 
-</​code>​ 
- 
-리스트를 제외한 나머지 자료구조는 인덱스나 키로 요소를 가져올 수 있다. 
- 
-<code clojure> 
-; 벡터는 인덱스로 값을 가져온다. 
-([1 2 3] 0) ;=> 1 ; 벡터의 첫 요소는 0는 인덱스 번호 0이다. 
-([1 2 3] 3) ;=> nil ; 인덱스 번호 3은 네번째 요소로 존재하지 않는다. 
- 
-; 맵은 키로 값을 가져온다. 
-({:a 1 :b 2 :c 3} :a) ;=> 1   ;​=>​ :a키에 해당하는 값은 1이다. 
-({:a 1 :b 2 :c 3} :d) ;=> nil ;=> :d라는 키는 없기 때문에 nil을 리턴 
-({:a 1 :b 2 :c 3} :d 4) ;=> 4 ;=> 맵에 해당키가 없는 경우 디폴트 값을 지정할 수 있다. 
- 
-; 집합은 요소 자신을 통해 값을 가져온다. (결국 존재여부 확인) 
-(#{1 2 3} 1) ;=> 1  ; 집합은 값과 키가 같은 맵이라고 생각하면 된다. 앞의 집합은 {1 1 2 2 3 3} 맵으로 생각할 수 있다. 
-(#{1 2 3} 0) ;=> nil ; 앞의 집합에서 1은 있으나 0은 없다. 
-</​code>​ 
- 
-get 함수를 통해 명시적으로 요소를 가져올 수 있다. 
- 
-<code clojure> 
-(get [1 2 3] 0) ;=> 1 ; 인덱스는 0부터 시작한다. 
- 
-(get {:a 1 :b 2 :c 3} :a) ;=> 1    
-(get {:a 1 :b 2 :c 3} :d) ;=> nil  
-(get {:a 1 :b 2 :c 3} :d 4) ;=> 4 ; 4는 디폴트 값. 
- 
-(get #{1 2 3} 1) ;=> 1  ​ 
-(get #{1 2 3} 0) ;=> nil 
-</​code>​ 
- 
-get 함수를 통하면 벡터와 집합에 해당 요소가 없을 경우 디폴트 값을 지정할 수 있다. 
- 
-<code clojure> 
-(get [1 2 3] 3) ;=> nil 
-(get [1 2 3] 3 100) ;=> 100 
- 
-(get #{1 2 3} 0) ;=> nil 
-(get #{1 2 3} 0 100) ;=> 100 
-</​code>​ 
- 
-맵에서 해당키의 값이 nil일 경우, contains?​로 키의 존재 여부를 확인할 수 있다. 
- 
-<code clojure> 
-({:a nil} :b) => nil 
-({:a nil} :a) => nil 
-(contains? {:a nil} :a) ;=> true 
-</​code>​ 
- 
-벡터는 nth로도 값을 가져올 수 있다. 
- 
-<code clojure> 
-(nth [1 2 3] 0) ;=> 1 
-(nth [1 2 3] 3) ;=> 예외(IndexOutOfBoundsException) 발생 
-(nth [1 2 3] 3 3) ;=> 3 
-</​code>​ 
-==== 자료구조에 추가/​삭제 : cons/​conj/​pop/​disj/​assoc/​dissoc/​assoc-in ==== 
- 
-=== 리스트에 추가 === 
- 
-<code clojure> 
-(cons 0 '(1 2 3)) ;=> (0 1 2 3) 
-(conj '(1 2 3) 4) ;=> (4 1 2 3) 
-(pop '(1 2 3)) ;=> (2 3) 
-</​code>​ 
- 
-Clojure는 코딩시 (1 2 3) 하면 위에서 함수를 설명한 것처럼 괄호()의 첫 요소인 1을 함수로 평가하게 되는데, 1은 함수가 아니기 때문에 예외가 발생한다. Clojure 컴파일러가 괄호()를 평가하지 않고 그냥 리스트로 인식하게 하기 위해서는 '(1 2 3) 처럼 하면 된다. 
- 
-cons는 새로운 리스트를 만든다. 새로운 리스트의 첫 요소는 첫번째 파라미터이고,​ 나머지는 두번째 파라미터의 요소들이다. 
- 
-conj(oin)는 리스트에 새 요소를 추가하는데,​ 리스트에 추가하는 가장 빠른 방법은 앞에 추가하는 것이다. ​ 
- 
-=== 벡터에 추가 === 
- 
-<code clojure> 
-(cons 0 [1 2 3]) ;==> (0 1 2 3) 
-(conj [1 2 3] 4) ;==> [1 2 3 4] 
-(pop [1 2 3]) ;=> [1 2] 
-</​code>​ 
- 
-cons는 그 대상이 벡터여도 결과는 같다. 즉 맨 앞에 추가한 리스트를 리턴한다. 
- 
-conj는 벡터일 때는 맨 뒤에 추가한다. 벡터는 인덱스 접근이 가능하기 때문이다. 
- 
- 
-=== 집합에 추가/​삭제 === 
- 
-<code clojure> 
-(conj #{1 2 3} 4) ;=> #{1 2 3 4} ; 추가 
-(disj #{1 2 3} 3) ;=> #{1 2}     ; 삭제 
-</​code>​ 
- 
-=== 맵에 추가/​삭제 === 
- 
-<code clojure> 
-(assoc {:a 1} :b 2) ;=> {:a 1 :b 2} ; 추가 
-(assoc {:a 1} :b 2 :c 3 :d 4) ;=> {:a 1 :b 2 :c 3} ; 추가 
-(dissoc {:a 1 :b 2} :b) ;=> {:a 1}  ; 삭제 
- 
-</​code>​ 
- 
-==== assoc-in / update-in ==== 
- 
-<code clojure> 
-(assoc-in {:a {:x 1}} [:a :x] 100) ;=> {:a {:x 100}} 
-(update-in {:a {:x 1}} [:a :x] inc) ;=> {:a {:x 2}} 
- 
-</​code>​ 
-==== 자료 구조에 접근하는 함수 : first/​second/​last/​rest ==== 
- 
-<code clojure> 
-(first '(1 2 3 4 5)) ;=> 1 
-(second '(1 2 3 4 5)) ;=> 2 
-(last '(1 2 3 4 5)) ;=> 5 
-(rest '(1 2 3 4 5)) ;=> (2 3 4 5) 
-</​code>​ 
- 
-==== ffirst/​next/​butlast/​fnext/​nfirst === 
- 
-<code clojure> 
-(ffirst [[1] [2]]) ;=> 1 ;(first (first x)) 와 같다 
-(next [1 2 3 4 5]) ;=> (2 3 4 5) ;rest와 같다. 마지막 요소가 없으면 nil을 리턴 
-(next []) ;=> nil 
-(butlast [1 2 3 4 5]) ;=> (1 2 3 4) ;​마지막을 제외한 리스트 
-(fnext [1 2 3]) ;=> 2 ;(first (next x)) 와 같다. 
-(nfirst [[1 2] 3]) ;=> 2 ;(next (first x)) 와 같다. 
-</​code>​ 
- 
-==== rest와 next의 차이 ==== 
- 
-<code clojure> 
-(rest [1 2 3]) ;=> (2 3) 
-(next [1 2 3]) ;=> (2 3) 
- 
-(rest []) ;=> () 
-(next []) ;=> nil 
-</​code>​ 
- 
- 
- 
-==== take/drop ==== 
- 
-(take n coll) 
-coll의 처음 n개의 요소로 된 lazy-seq를 리턴한다. 
- 
-<code clojure> 
-(take 3 '(1 2 3 4 5 6)) ;=> (1 2 3) ; 리스트를 받아 lazy-seq를 리턴 
-(take 3 [1 2 3 4 5 6) ;=> (1 2 3)   ; 벡터를 받아 lazy-seq를 리턴 
-(take 3 [1 2]) ;=> (1 2)  ​ 
-</​code>​ 
- 
-(drop n coll) 
-coll의 처음 n개의 요소를 제외한 나머지로 된 lazy-seq를 리턴한다. 
- 
-<code clojure> 
-(drop 3 '(1 2 3 4 5 6)) ;=> (4 5 6) 
-(drop 3 [1 2 3 4 5 6]) ;=> (4 5 6) 
-(drop 3 [1 2]) ;=> ()  ​ 
-</​code>​ 
- 
-==== take-while/​drop-while ==== 
- 
-(take-while pred coll) 
- 
-(pred el)이 참인 동안의 요소들로 된 lazy-seq를 리턴한다. 즉 처음 (pred el)이 거짓일 때까지의 요소로 된 lazy-seq. 
- 
-<code clojure> 
-(take-while neg? [-2 -1 0 1 2 3]) ;=> (-2 -1) 
-(take-while neg? [-2 -1 0 -1 -2 3]) ;=> (-2 -1) 
-</​code>​ 
- 
-(drop-while pred coll) 
- 
-(pred el)이 참인 동안의 요소들을 제외한 나머지 요소로 된 lazy-seq를 리턴한다. 즉 처음 (pred el)이 거짓일 때까지의 요소 제외한 lazy-seq. 
- 
-<code clojure> 
-(drop-while neg? [-1 -2 -6 -7 1 2 3 4 -5 -6 0 1]) ;=> (1 2 3 4 -5 -6 0 1) 
-</​code>​ 
-==== for ==== 
- 
-<code clojure> 
-(for [n (range 5)] 
- n) 
-;=> (0 1 2 3 4) 
- 
-(for [n (range 5)] 
- (+ n n) 
-;=> (0 2 4 6 8) 
- 
-(for [x ['a 'b '​c] ​ 
-      y [1 2 3]] 
-  [x y]) 
-;=> ([a 1] [a 2] [a 3] [b 1] [b 2] [b 3] [c 1] [c 2] [c 3]) 
-</​code>​ 
- 
-clojure에서 for는 제어구조가 아니라 매크로다. 그리고 리스트를 리턴한다. 이것이 다른 언어와 다른 점이다. 
- 
-for는 매우 막강한 기능을 갖는다. clojuredoc.org의 for 예제 샘플은 for의 막강한 기능을 잘 보여준다. 
- 
-(참고: http://​programming-puzzler.blogspot.kr/​2013/​03/​logic-programming-is-overrated.html) 
- 
-다음은 그중 일부이다. 
- 
-<code clojure> 
-(for [x [0 1 2 3 4 5] 
-      :let [y (* x 3)] 
-      :when (even? y)] 
-  y) 
-;=> (0 6 12) 
- 
-(for [x (range 1 6)  
-      :let [y (* x x)  
-            z (* x x x)]]  
-   [x y z])          ​ 
-;=> ([1 1 1] [2 4 8] [3 9 27] [4 16 64] [5 25 125]) 
-</​code>​ 
-==== map ==== 
- 
-(map f coll) 
- 
-map 함수는 다음과 같이 수학에서 한 집합에서 다른 집합으로 바꾸는 작업을 한다. f는 coll의 각 요소에 적용된다. 
- 
-     ​X ​                ​Y ​   
-   ​+----+ ​  (f x1)   ​+----+ 
-   | x1 |  -------> ​ | y1 | 
-   ​| ​   |   (f x2)   ​| ​   | 
-   | x2 |  -------> ​ | y2 | 
-   ​| ​   |   (f x3)   ​| ​   | 
-   | x3 |  -------> ​ | y3 | 
-   ​| ​   |   (f x3)   ​| ​   | 
-   | x4 |  -------> ​ | y4 | 
-   ​+----+ ​           +----+ 
-    
-  ​ 
-f가 inc이고 coll [1 2 3 4]인 경우 coll의 모든 요소에 inc가 적용된 lazy-seq가 리턴된다. 
-  
-<code clojure> 
-(map inc [1 2 3 4])  ;=> (2 3 4 5) 
-</​code>​ 
- 
-     ​X ​               Y    
-   ​+---+ ​ (inc 1)   +---+ 
-   | 1 | --------> ​ | 2 | 
-   ​| ​  ​| ​ (inc 2)   ​| ​  | 
-   | 2 | --------> ​ | 3 | 
-   ​| ​  ​| ​ (inc 3)   ​| ​  | 
-   | 3 | --------> ​ | 4 | 
-   ​| ​  ​| ​ (inc 4)   ​| ​  | 
-   | 4 | --------> ​ | 5 | 
-   ​+---+ ​           +---+ 
- 
-map 함수는 clojure programming에서 가장 많이 사용하는 함수이고 기능도 아주 다양하다. 
-clojuredocs.org에는 map함수를 활용하는 다양한 예제 샘플들이 아주 많다. 
- 
-==== filter/​remove ==== 
- 
-(filter pred coll) 
- 
-filter 함수는 coll의 요소 el에 대해 (pred el)이 참인 el들로 된 lazy-seq를 리턴한다. 
- 
-     ​X ​                             Y    ​ 
-   ​+----+ ​   (pred x1) = true     ​+----+ 
-   | x1 | ---------------------->​ | x1 | 
-   ​| ​   |    (pred x2) = false    |    | 
-   | x2 | ---------------------->​ |    | 
-   ​| ​   |    (pred x3) = true     ​| ​   | 
-   | x3 | ---------------------->​ | x2 | 
-   ​| ​   |    (pred x4) = false    |    | 
-   | x4 | ---------------------->​ |    | 
-   ​+----+ ​                        ​+----+ 
-    
-<code clojure> 
-(filter even? (range 10)) ;=> (0 2 4 6 8) 
-</​code>​ 
- 
-remove는 반대이다. 즉 (pred el)이 참이면 제거한다. 
- 
-<code clojure> 
-(remove even? (range 10)) ;=> (1 3 5 7 9) 
-</​code>​ 
- 
- 
-==== keep ==== 
- 
-(keep f coll) 
- 
-keep 함수는 coll의 요소 el에 대해 (f el)이 nil이 아닌 리턴값으로 된 lazy-seq를 리턴한다. 
- 
-     ​X ​                        ​Y ​   ​ 
-   ​+----+ ​   (f x1) = y1     ​+----+ 
-   | x1 | ----------------->​ | y1 | 
-   ​| ​   |    (f x2) = nil    |    | 
-   | x2 | ----------------->​ |    | 
-   ​| ​   |    (f x3) = y3     ​| ​   | 
-   | x3 | ----------------->​ | y3 | 
-   ​| ​   |    (f x4) = nil    |    | 
-   | x4 | ----------------->​ |    | 
-   ​+----+ ​                   +----+ 
- 
-<code clojure> 
-(keep #(if (odd? %) %) (range 10)) ;=> (1 3 5 7 9) 
-</​code>​ 
-==== reduce ==== 
- 
-(reduce f initial coll) 
- 
-reduce 함수는 coll의 요소 el에 대해 2개의 인수를 받는 함수 (f acc el)의 결과를 다음 el들의 f의 acc에 적용하여 누적한 최종값(acc)을 리턴한다. 
- 
- 
-    
-   (f initial x0) ;=> acc1 
-       ​|---------------| 
-       v 
-   (f acc1 x1)    ;=> acc2 
-       ​|---------------| 
-       ​v ​   
-   (f acc2 x2)    ;=> acc3 
-       ​|---------------| 
-       v 
-   (f accn xn)    ;=> acc (최종값) 
-    
-    
-initial이 주어지지 않으면 최초 f 호출시 첫요소 x0가 acc로, x1은 el로 해서 호출된다. 
- 
-<code clojure> 
-(reduce + [1 2 3 4 5]) ;=> 15 
-</​code>​ 
- 
-위 reduce가 수행되는 과정은 다음과 같다. 
- 
-initial이 주어지지 않아서 처음 acc는 1이고, 2는 두번째 파라미터가 된다. 
- 
-   (+ 1 2)   ;​=>​ 3 
-      |----------| 
-      v 
-   (+ 3 3)   ;​=>​ 6 
-      |----------| 
-      v    
-   (+ 6 4)   ;​=>​ 10 
-      |-----------| 
-      v 
-   (f 10 5)  ;=> 15 (최종값) 
- 
-reduce는 매우 강력한 함수이다. 이것만 잘 사용하면 왠만한 제어구조는 거의 소화할 수 있다. 
- 
-(reduce에서 reduce를 사용하는 매우 복잡한 일도 가능하게 되는데, 가급적 사용하지 않는 것이 코드의 가독성을 키우는데 좋다.) 
lecture/4clojure/level-elementary.txt · Last modified: 2019/02/04 14:26 (external edit)