기본문법
단순값
클로저 코드는 식으로 구성되며 그 식이 평가된 결과가 반환 된다. 이들 중 가장 단순한 것은 자기자신으로 평가 되는 식이다 → 단순값(simple value) 또는 리터럴(literal)이라 함
wonderland.core=> 12.43
12.43
wonderland.core=> 4/2
2
wonderland.core=> 1/3
1/3클로저에서 분수가 평가 될때 실수로 변환되지 않는것에 주목
wonderland.core=> (/ 1 3.0)
0.3333333333333333
wonderland.core=> "jam"
"jam"
wonderland.core=> :jam
:jam문자열 또한 자기 자신으로 평가되고, 클로저에서:(콜론) 을 사용하는 식별자가 존재하는데 keyword라고 부른다 keyword 또한 자기 자신으로 평가되고 클로저에서 매우 유용하게 사용된다
그 말고도 boolean, nil(java에서 null) 등 이 단순값이다
데이터 컬렉션
리스트 컬렉션
클로저에서 리스트를 만들려면 단순히 인용기호(‘)를 괄호 앞에 붙이고 데이터를 괄호 안에 넣으면 된다
wonderland.core=> '(1 2 "jam" :marmalade-jar)
(1 2 "jam" :marmalade-jar)리스트 요소간 쉼표로 구분할수 있지만 일반적이지 않다고 한다 (그냥 공백으로 구분하는게 일반적)
wonderland.core=> (first '(:rabbit :pocket-watch :marmalade :door))
:rabbit
wonderland.core=> (rest '(:rabbit :pocket-watch :marmalade :door))
(:pocket-watch :marmalade :door)first와 rest 로 첫번째 인자와 첫번째를 제외한 인자를 반환 받을 수 있다
wonderland.core=> (cons 10 `(1 2 3 4))
(10 1 2 3 4)
wonderland.core=> (cons 4 (cons 5 nil))
(4 5)cons는 두개의 인자를 받게끔 되어 있는데 기존 리스트에 값을 추가할수 있고, 마지막 요소를 nil로 만들면서 리스트를 만들 수 있다
벡터 컬렉션
벡터는 아주 편리해서 클로저에서 많이 쓰인다, 대괄호를 둘러싸서 만든다
wonderland.core=> [:jar 1 2 3 :jar3]
[:jar 1 2 3 :jar3]
wonderland.core=> (last [:jar 1 2 3 :jar3])
:jar3
wonderland.core=> (nth [:jar 1 2 3 :jar3] 4)
:jar3리스트와 마찬가지로 first, rest 명령어를 사용할 수 있고, 벡터는 last 명령어를 통해 마지막 요소의 값을 반환할 수 있다
그리고 nth를 통해 특정 인덱스에 존재하는 요소의 값을 반환할 수 있다
title: 리스트와 벡터 접근
![[IMG_4501.jpg|500]]
*리스트에서도 last, nth 를 사용할 순 있지만, 벡터의 인덱스 접근 성능이 더 좋다*
따라서 인덱스로 컬렉션의 요소에 접근할 필요가 있다면 벡터를 쓴다맵, 키-값 쌍의 데이터 컬렉션
기본적인 쓰임
wonderland.core=> (get {:jam "strawberry"} :jam)
"strawberry"
wonderland.core=> (get {:jam :strawberry} :jam)
:strawberry
wonderland.core=> (get {"jam" :strawberry} "jam")
:strawberry
wonderland.core=> (get {1 "strawberry"} 1)
"strawberry"
wonderland.core=> (get {[1 2 3] "strawberry"} [1 2 3])
"strawberry"중괄호를 통해 키와 값의 쌍을 공백으로 구분하여 저장할 수 있다 → 쉼표로 키값을 구분해도 상관없다 그리고 위와같이 맵컬렉션을 만들때 형식에 크게 구애 받지 않는 것을 알수 있다 → 단순식으로 평가되는것들은 전부 키로 가능한 것으로 보인다
검색
wonderland.core=> (get {:jam "strawberry"} :jam2 "not found")
"not found"
wonderland.core=> (:jam2 {:jam "strawberry" :jam2 "blueberry"})
"blueberry"
wonderland.core=> (keys {:jam "strawberry" :jam2 "blueberry"})
(:jam :jam2)
wonderland.core=> (vals {:jam "strawberry" :jam2 "blueberry"})
("strawberry" "blueberry")위와 같이 get 을 사용해서 키 값을 찾을 때 default값을 두어 찾지 못할 경우 반환되는 값을 지정해줄수 있고
get대신 그냥 키 자체를 사용해서 반환값을 나오게 할수도 있다
keys, vals 으로 키들만, 값들만 반환할수도 있다
수정 및 삭제
wonderland.core=> (assoc {:jam1 "red" :jam2 "black"} :jam1 "orange")
{:jam1 "orange", :jam2 "black"}
wonderland.core=> (assoc {:jam1 "red" :jam2 "black"} :jam3 "orange")
{:jam1 "red", :jam2 "black", :jam3 "orange"}
wonderland.core=> (dissoc {:jam1 "strawberry" :jam2 "blackberry"} :jam2)
{:jam1 "strawberry"}
wonderland.core=> (merge {:jam1 "red" :jam2 "black"}
#_=> {:jam1 "orange" :jam3 "red"}
#_=> {:jam4 "blue"})
{:jam1 "orange", :jam2 "black", :jam3 "red", :jam4 "blue"}assoc 을 통해 기존의 값을 업데이트 하거나 새로운 키값쌍을 추가할 수있고,
dissoc 을 통해 키값쌍을 맵에서 지울 수 있다
그리고 merge 를 통해 서로 다른 맵 컬렉션을 하나로 합칠수 있다
당연히 기존컬렉션을 수정하는 것은 아니고 새로운 컬렉션에 기존요소들을 추가하고 수정할 요소만 따로 바꿔주는 식으로 해주는 식이다
집합 컬렉션
기본 쓰임
wonderland.core=> #{:red :white :pink}
#{:white :red :pink}
wonderland.core=> #{:red :white :pink :pink}
Syntax error reading source at (REPL:1:27).
Duplicate key: :pink집합은 샵중괄호(#{}) 를 통해 만들 수 있다, 집합이기 때문에 처음 선언 및 초기화 시에 키가 중복되면 에러가 난다
집합 연산
clojure.set울 붙여서 집합 연산(합, 교, 차) 을 해 줄 수 있다
;; 합집합
wonderland.core=> (clojure.set/union #{:r :b :w} #{:w :p :y})
#{:y :r :w :b :p}
;; 차집합
wonderland.core=> (clojure.set/difference #{:r :b :w} #{:w :p :y})
#{:r :b}
;; 교집합
wonderland.core=> (clojure.set/intersection #{:r :b :w} #{:w :p :y})
#{:w}Set으로 집합으로 만들기
wonderland.core=> (set [:rabbit :rabbit :watch :door])
#{:door :watch :rabbit}
wonderland.core=> (set '(:rabbit :rabbit :watch :door))
#{:door :watch :rabbit}set 을 통해 벡터나 리스트 등 다른 컬렉션을 집합으로 만들어 줄 수 있다
title: 그럼 다른 컬렉션들은 어떨까
당연히 다른컬렉션도 서로 변환해주는 명령어가 있을거 같아서 간단하게 찾아보니
```Clojure
;; 벡터 -> 리스트, list* 로 만들어줄 수 있다
wonderland.core=> (list* [:r :b :w])
(:r :b :w)
;; 리스트 -> 벡터 vec 으로 만들어줄 수 있다
wonderland.core=> (vec '(1 2 3))
[1 2 3]
```탐색 및 삭제
;; 집합 컬렉션
wonderland.core=> (contains? #{:a :c :d :w} :a)
true
;; 맵 컬렉션
wonderland.core=> (contains? {:a "s" :c "w" } :a)
true
wonderland.core=> (disj #{:rabbit :door} :door)
#{:rabbit}contains? 는 해당 컬렉션에 키가 존재하는지 알려주는 명령어이다
따라서 키로 이루어지지 않는 컬렉션에서는 사용하지 못한다
그리고 disj 명령어로 집합에서 요소를 제거해 줄수 있다
컬렉션들의 공통점
모든 컬렉션은 불변(immutable) 이고 존속적(persistent) 이다 불변이란 컬렉션의 값이 변하지 않는다는 것을 의미하고, 컬렉션에 요소를 cons로 요청하게 되면, 원래의 컬렉션이 변하는 것이 아니고 단지 그 요소가 추가된 새로운 버전의 컬렉션이 반환되는 것이다
존속이란 구조공유(structual sharing)라는 기법으로 컬렉션의 신규 버전이 효율적으로 만들어진다는 것을 의미한다
;; 벡터
wonderland.core=> (conj [:toast :butter] :jam)
[:toast :butter :jam]
;; 리스트
wonderland.core=> (conj `(:toast :butter) :jam :berry)
(:berry :jam :toast :butter)벡터에 conj를 통해 요소를 추가하는 경우 와 리스트에 conj를 통해 요소를 추가하는 것이 다르게 추가되는 것을 볼수 있는데
해당 데이터 구조에 가장 효율적으로 컬렉션에 요소를 추가하는 것이다 → 이러한 것이 존속적이라는 것 같다
요약
클로저의 단순값
- 문자열
- 정수
- 분수
- 실수
- 키워드
- 문자
- 불린
클로저의 컬렉션
- 리스트는 맨 앞에서부터 접근할수 있는 데이터 컬렉션
- 벡터는 임의의 위치로 접근할 수 있는 데이터 컬렉션
- 맵은 키-값 쌍들로, 데이터를 구성하고 쉽게 접근하는데 좋다
- 집합은 유일한 요소들의 컬렉션으로, 집합연산이 가능하다
