Created
March 11, 2019 04:34
-
-
Save guruma/f3ad56c5eba77943f1f8099a19bbd02d to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(ns ch3.core) | |
;;;;;;;;;;;;;; | |
;; Chapter 3 | |
;;;;;;;;;;;;;; | |
;; 리스트는 앞에 추가한다. | |
(def lst '(1 2 3)) | |
(conj lst 0) | |
(conj lst 0 -1) ; 여러개 추가 가능 | |
(seq lst) | |
;; 벡터는 뒤에 추가한다. | |
(def v [1 2 3]) | |
(conj v 4) | |
(conj v 4 5) | |
(seq v) | |
(def m {:a 5 :b 6}) | |
(conj m [:c 7]) | |
(conj m [:c 7] [:d 8]) | |
(seq m) | |
(def s #{1 2 3}) | |
(conj s 4) | |
(conj s 3 4) | |
(seq s) | |
;; conj nil | |
(conj nil 3 4) | |
;; into 리스트는 앞에 추가 | |
(into '(1 2 3) [:a :b :c]) | |
(defn swap-pairs [sequential] | |
(into (empty sequential) | |
(interleave | |
(take-nth 2 (drop 1 sequential)) | |
(take-nth 2 sequential)))) | |
(empty [1 2]) | |
(swap-pairs (apply list (range 10))) | |
(swap-pairs (apply vector (range 10))) | |
(defn map-map [f m] | |
(into (empty m) | |
(for [[k v] m] | |
[k (f v)]))) | |
(map-map inc (hash-map :z 5 :c 6 :a 0)) | |
(map-map inc (sorted-map :z 5 :c 6 :a 0)) | |
;; Sequence 추상 | |
;; | |
;; seq 함수 : 각 타입의 시퀀스 뷰 제공 | |
;; 인터페이스 함수 : first, rest, next | |
;; clojure.lang.ISeq | |
;; | |
;; 시퀀스는 리스트가 아니다. | |
;; 리스트는 eliment 모은 collection이지만 | |
;; 시퀀스는 head와 tail로 된 pair(tuple)이다. 즉 시퀀스에는 eliment라는 개념이 없다. | |
;; https://books.google.co.kr/books?id=4QacPa1vwMUC&pg=PA76&lpg=PA76&dq=practical+clojure+sequence+illustration&source=bl&ots=2AECdpi3oc&sig=ACfU3U2UabuOn0Zv04bArk-xo8DSE-gFfw&hl=ko&sa=X&ved=2ahUKEwjQnM3UpfTgAhUowosBHcKjB1YQ6AEwAHoECAIQAQ#v=onepage&q=practical%20clojure%20sequence%20illustration&f=false | |
;; sequable types | |
;; | |
;; All Clojure collection types | |
;; All Java collections (i.e., java.util.*) | |
;; All Java maps | |
;; All java.lang.CharSequences, including Strings | |
;; Any type that implements java.lang.Iterable | |
;; Arrays | |
;; nil (i.e., null as returned from Java methods) | |
;; Anything that implements Clojure’s clojure.lang.Seqable interface | |
(seq "Clojure") | |
(seq {:a 5 :b 6}) | |
(seq (java.util.ArrayList. (range 5))) | |
(seq (into-array ["Clojure" "Programming"])) | |
(if (seq [])) | |
(seq nil) | |
(not (empty? nil)) | |
;; 대부분의 함수들이 내부적으로 인자에 seq를 호출해서 사용하기 때문에, seq를 해서 넘길 필요가 없다. | |
(map str "Clojure") | |
(set "Programming") | |
;; clojure.lang.ISeq | |
;; https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/ISeq.java | |
;; https://clojure.org/reference/sequences | |
(map seq? ['() [] #{} {}]) | |
(map sequential? ['() [] #{} {}]) | |
(map coll? ['() [] #{} {}]) | |
;(map seqable? ['() [] #{} {}]) ; clojure 1.9 | |
;= [true true true true] | |
(clojure-version) | |
(rest [1]) | |
(next [1]) | |
(rest []) | |
(next []) | |
(rest nil) | |
(next nil) | |
(def x '()) | |
(= (next x) | |
(seq (rest x))) | |
(type (range 10)) | |
(list? (range 10)) | |
;; 시퀀스는 이터레이터가 아니다. | |
(doseq [x (range 3)] | |
(println x)) | |
(let [r (range 3) | |
rst (rest r)] | |
(prn (map str rst)) | |
(prn (map #(+ 100 %) r)) | |
(prn (conj r -1) (conj rst 42))) | |
;; 시퀀스는 리스트가 아니다. | |
;; 리스트는 길이 정보를 관리한다. 그래서 length를 하면 바로 길이를 리턴한다. | |
(let [s (range 1e6)] | |
(time (count s))) | |
(let [s (apply list (range 1e6))] | |
(time (count s))) | |
;; 시퀀스 만들기 | |
(type (cons 0 (range 1 5))) | |
(cons :a [:b :c :d]) | |
(cons 0 (cons 1 (cons 2 (cons 3 (range 4 10))))) | |
(type (list* 0 1 2 3 (range 4 10))) | |
(type (list 1 2 3)) | |
;; lazy-seq | |
;; clojure 1.2에서는 lazy-cons를 사용했는데 없어지고 lazy-seq를 사용한다. | |
;; collection define X, access O | |
(type (lazy-seq [1 2 3])) | |
(defn random-ints | |
"Returns a lazy seq of random integers in the range [0,limit)." | |
[limit] | |
(lazy-seq | |
(cons (rand-int limit) | |
(random-ints limit)))) | |
(take 10 (random-ints 50)) | |
;; (1.f) | |
;; (1.(2.f)) | |
;; lazy-seq, realized | |
(defn random-ints [limit] | |
(lazy-seq | |
(log "realizing random number") ; side effect, 관문 | |
(cons (rand-int limit) | |
(random-ints limit)))) | |
(def rands (take 10 (random-ints 50))) | |
(first rands) | |
(nth rands 3) | |
(count rands) | |
(count rands) | |
;; lazy-seq = value -> thunk | |
(repeatedly 10 (partial rand-int 50)) | |
(def x (next (random-ints 50))) ; head rest | |
(def x (rest (random-ints 50))) ; head | |
(doall (take 5 (random-ints 50))) ; retention | |
(dorun (take 5 (random-ints 50))) ; dumped out | |
;; doc을 보면 lazy-seq인지 여부를 알 수 있다. | |
iterate | |
reverse | |
;; lazy-seq는 define할 때가 아니라, access할 때 realized 되기 때문에 | |
;; side-effect가 뒤늦게 발생할 수 있다. | |
;; 예를 들어 로깅의 경우, realized 될 때 로깅이 된다면, 어느 순간 로깅이 켜지거나 꺼질 때 | |
;; 로깅이 되기도 하고 안되기도 하는 문제가 발생할 수 있다. | |
;; 게다가, 경우에 따라 어떤 lazy-seqs는 성능상 chunk 단위로 한꺼번에 realized 하는 경우도 있다. | |
;; 예들 들어 vector의 경우 32개의 요소 단위로 chunk된 시퀀스를 만든다. | |
;; 이런 경우, 어떤 하나의 요소에 access해도 32개의 realization이 발행할 수 있다. | |
;; 따라서, 클로저의 lazy-seq를 제어 흐름의 도구로 사용하면 안된다. | |
;; 계산 과정의 일시적 매개체로서의 시퀀스 | |
(apply str (remove (set "aeiouy") | |
"vowels are useless! or maybe not...")) | |
(remove #{1 2 5} (range 10)) | |
; lazy-seq retention | |
; | |
;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
;; head retention | |
;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
(split-with neg? (range -5 5)) | |
;= [(-5 -4 -3 -2 -1) (0 1 2 3 4)] | |
;(let [[t d] (split-with #(< % 12) (range 1e8))] | |
; [(count d) (count t)]) | |
;= #<OutOfMemoryError java.lang.OutOfMemoryError: Java heap space> | |
(let [[t d] (split-with #(< % 12) (range 1e8))] | |
[(count t) (count d)]) | |
;= [12 99999988] | |
;; https://stackoverflow.com/questions/15994316/clojure-head-retention/21803773 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment