2016년 11월 24일 목요일

[Java Reflection REVIEW] 자바 리플렉션 사용기- 01



I'm a Java developer. As a Java developer. There are many annoying things in workspace while I'm working. Such as Using MAP!!!! Let's say. You're going to put Info data into Map

Info info = new Info("name", "password", "alias", "address", "strength",
                     "etc1", "etc2");

Map map = new HashMap();
map.put("name",info.getName());
map.put("password",info.getPassword());
map.put("alias",info.getAlias());
map.put("address",info.getAddress());
map.put("strength",info.getStrength());
map.put("etc1",info.getEtc1());
map.put("etc2",info.getEtc2());
I've found tons of lines of codes In my workspace. As a junior Programmer, By the way I've worked as a programmer just about 5 months, I asked my comapany "How can we fix it? This is really annoying?" But they said "I don't know Why you are asking. This is What it is. It is not an error." So I've tried using Java Reflection. It is very Simple that you can easily use it. first. Create Getters
private String craeteGetMethod(String arg) {
 StringBuffer buffer = new StringBuffer(10);
 buffer.append("get");
 buffer.append(arg.substring(0, 1).toUpperCase());
 buffer.append(arg.substring(1));
 return buffer.toString();
}
Simple so When You put "name" in it. You'll get "getName". Second. Create Invoking Method
private String invokeMethod( String methodName, Object obj) {
  String res = null;
    Method me;
      try {
    
 me = obj.getClass().getMethod(methodName);
 res = (String)me.invoke(obj);
    
 } catch (Exception e) {
   e.printStackTrace();
 }

    return res;
}
Third. Gather Method and Invoke All
private void ObjectToMap(Map map, List methods, Object sms) {
  for ( String key : methods) {
    String methodName = craeteGetMethod(key);
    invokeMethod(methodName, sms);
    map.put(key, invokeMethod(methodName,sms));
  }
}
I should have finished refactoring. but this will be enough in this page.
Info info = new Info("name", "password", "alias", "address",
 "strength", "etc1", "etc2");

Map map = new HashMap();
ObjectToMap(map, Arrays.asList("name", "password", "alias",
 "address", "strength", "etc1", "etc2"), info);
But It's really slow If you are going yo use reflection to put a massive datas into Database. This is not for you. thank you for stopping by. I will be happy with your comments.

2016년 11월 23일 수요일

[clojure-docs]assoc-in



assoc-in

assoc-in은 정말 어려운 함수이다. 정말 처음엔 뭐 이런게 있나 싶다.
(assoc-in {} [:cookie :monster :vocals] "Finntroll")
{:cookie {:monster {:vocals "Finntroll"}}}
이것은 잘 보자. {}안에 :cookie 안에 :monster 안에 :vocals 안에 "Finntroll"을 넣는 것이다. 그렇다면 이걸보자. 내가 임의로 비슷한 함수를 만들었다.
((fn [new-board [p1 p2] neighbor] (assoc-in new-board [p1 :connections p2] neighbor)) {} [1 3] 4  )
{1 {:connections {3 4}}}
보면 assoc-in은 new-board안에 순서대로 넣는 것이다. {} 안에 1 그리고 그 1안에 :connections 그리고 그 안에 3 그리고 그 값으로 4를 넣은 것이다. 정리하면 assoc의 매개변수는 순서대로 1. 값을 들어갈 곳 2. 키값의 덩어리들 3. 키값 안에 들어가 숨어있을 값 좀 더 이해를 위해 get-in을 사용해보자.
(get-in {1 {:connections {3 4}}} [1])
{:connections {3 4}}

(get-in {1 {:connections {3 4}}} [1 :connections])
{3 4}

[clojure-doce][tip] 함수만들기의 이상한 아규먼트



내가 의아하게 본 소스가 이거다.
(defn a [new-board [a b]]
...
)
뭐 이런 식으로 만들어지는 함수를 보았는데 참으로 신기했다. 그래서 하나씩 다 넣어봤는데 결과를 얻었다. 잘 보자.
(defn a [new-board [a b]]
  new-board
)

(a [1] [2 3])
[1]
나머지 a, b도 무엇인지 보자.
(defn a [new-board [a b]]
  a
)

(a [1] [2 3])
2

(defn a [new-board [a b]]
  b
)

(a [1] [2 3])
3

[clojure-docs]memoize



memoize

클로저에서 값은 불면하다. 그렇기에 이런 이상한 일이 가능한 것인데 호출한 함수를 메모리에 올려서 기억시키는 일이다. (memoize: 이전에 계산한 값 자체를 저장하여 프로그램 실행 시간을 빠르게 하는 기술)
(defn sleep [x] (Thread/sleep 1000) x)

(sleep "Mr.KIM")
"Mr.KIM"

(sleep "Mr.KIM")
"Mr.KIM"
당연히 둘다 잘 나올 것이다. 단 3초 뒤에 나오는 것이다. 만약 이 3초가 강제로 잠재운 것이 아니라 오랜 시간 동안 계산해서 얻어내야 하는 값이라면?
(def memo-sleep (memoize sleep))

(memo-sleep "Mr.KIM")
"Mr.KIM"

(memo-sleep "Mr.KIM")
"Mr.KIM"
값은 같지만 두번째로 호출 할때 3초를 쉬지않고 바로 일을 한다. 왜냐하면 값을 이미 가지고 있기 때문ㅇ

[clojure-docs]Decision-Making 조건문



조건문

tutorial point에는 다섯개의 조건문을 소개한다. if if/do nested if case cond

if

user=> (defn one? [x]
  #_=>     (if (= x 1)
  #_=>       (println "EQUAL!!!!")
  #_=>       (println "no...")))
#'user/one?
user=> (one? 1)
EQUAL!!!!
nil

if/do

if문의 큰 단점이 있는데 그것은 하나만 할 수 있다는 것이다. 그래서 do를 붙인다. 일단 보자.
user=> (defn two? [x]
  #_=>   (if (= x 2)
  #_=>     (do (println "TWO!!!!")
  #_=>         (one? x))
  #_=>     (do (println "not Two")
  #_=>         (one? x))))
#'user/two?
user=> (two? 1)
not Two
EQUAL!!!!
nil
여러 개의 일을 do안에 넣는 것이다.

nested if

(defn Example [] (
   if ( and (= 2 2) (= 3 3))
   (println "Values are equal")
   (println "Values are not equal")))
(Example)
그냥 and를 사용할 수 있다는 점을 기억하기 바란다.

case

case expression
value1 statement #1
value2 statement #2
valueN statement #N
statement #Default
case문이라고 생각하면 될듯하다.
user=> (defn score [x]
  #_=>   (case x
  #_=>   10 (println "score 10")
  #_=>   (println "not 10")))
#'user/score
user=> (score 10)
score 10
nil

cond

cond
(expression evaluation1) statement #1
(expression evaluation2) statement #2
(expression evaluationN) statement #N
:else statement #Default
그냥 condition이라 생각하면 편하다
(defn Example []
   (def x 5)
   (cond
      (= x 5) (println "x is 5")
      (= x 10)(println "x is 10")
      :else (println "x is not defined")))
(Example)

[clojure-docs]loop 루프


loops

클로저에서 반복문 덩어리들을 죄다 살펴보자. tutorial point에는 4가지 반복문이 소개되고 있다. while doseq dotimes loop

while

(while(expression)
   (do
      codeblock))
while문의 expression이 true인 동안만 codeblock을 실행시키는 것이다.
(let [x 10 y (atom 0)]
    (while (< @y x)
      (do
        (println @y)
        (swap! y inc))))
0
1
2
3
4
5
6
7
8
9
nil

doseq

(doseq (sequence)
   statement#1)
doseq는 'foreach'문과 비슷하다. 일단 보면서 foreach문을 연상하자.
(def seq [1 2 3 4 5 6 7])

(defn go [seq]
  (doseq [n seq]
    (println n)))

(go seq)
1
2
3
4
5
6
7
nil

dotimes

(dotimes [n 10]
    (println n))
1
2
3
4
5
6
7
8
9
nil
횟수만큼 index가 돈다고 생각하면 된다.

loop

loop [binding]
(condition
   (statement)
   (recur (binding)))
loop는 for-loop를 말하는 것이 아님. loop은 let처럼 값을 바인딩하고 recursion포인트를 지정한다. (그러니 재귀로 돌아갈 곳을 지정한다)
(loop [x 10]
    (if (< x 1)
      x
      (recur (- x 1))))
0

2016년 11월 21일 월요일

[clojure-docs] ->



->

-> 이건 사실 없어도 된다. 괄호의 지옥에서 벗어나기 위해 만들어진 창과 같은 것이다. 링크에 있는 예제를 보자.
(first (.split (.replace (.toUpperCase "a b c d") "A" "X") " "))
"X"

(-> "a b c d" 
           .toUpperCase 
           (.replace "A" "X") 
           (.split " ") 
           first)
"X"
괄호만 있을 때 보다 화살표로 만들어진 것이 더 읽기 쉽다.

2016년 11월 20일 일요일

[clojure-docs]comp



comp

comp함수는 함수 여러개를 같이 실행시키게 되는 것이다.
((comp str +) 8 8 8)   ;;=> "24"
기억해야 할 것은 오른쪽에서 왼쪽으로 실행한다는 것이다 comp를 써서 문자 속성 값을 얻는 방법
(def character
  {:name "Smooches McCutes"
   :attributes {:intelligence 10 :strength 4 :dexterity 5}})

(def c-int (comp :intelligence :attributes))
(def c-str (comp :strength :attributes))
(def c-dex (comp :dexterity :attributes))

(c-int character)
10
(c-str character)
4
(c-dex character)
5
이게 뭐야? 왜 저런 값이 나오는 거지? 라고 생각할 수 있다. 자 comp가 어디서부터 실행된다고? 오른쪽에서 왼쪽으로
(#(:intelligence (:attributes %)) character)
10
(#(:strength (:attributes %)) character)
4
(#(:dexterity (:attributes %)) character)
5
이렇게 되는 것과 같다. 어떻게 이렇게 되는 건가?
(defn two-comp
  [f g]
  (fn [& args]
    (f (apply g args))))

[clojure-docs]assoc



assoc

(assoc {} :key1 "value" :key2 "another value")
{:key2 "another value", :key1 "value"}
딱 보면 알듯이 {}안에 다 넣는 것이다.
(assoc nil :key1 4)
{:key1 4}
(assoc {} nil nil)
{nil nil}

[clojure-docs][tip] parse



parse

parse에 사용할 만한 아주 단순한 패턴이다.
(defn parse
  "Convert a CSV into rows of columns"
  [string]
  (map #(clojure.string/split % #",")
    (clojure.string/split string #"\n")))
순간 이게 뭔가 싶었다.
(clojure.string/split string #"\n")
이것만 일단 실행해보자.
자 이렇게 벡터로 만들어진다. 이거에서 하나하나 쉼표로 나누려면 map으로 하는 것이다. 하나씩 나누는 것이다. 

[clojure-docs]spit, slurp



slurp

spit은 파일을 쓰는데, slurp는 파일을 읽는 데 사용할 수 있다.
(spit "test.log" "hello mate?\n")
nil
(slurp "test.log")
"hello mate?\n"
특이한 것은 읽고 쓰는 함수의 이름이 spit (침을 퉷! 뱉는 것 같이 무언갈 뱉어내는 행위) 이라는 것이 흥미롭다. 물론 slurp도 마찬가지.

2016년 11월 19일 토요일

[clojure-docs] apply



apply

apply는 배열로 만들 수 있는 자료 구조를 부시고 각각의 매개변수를 취하는 함수로 전달할 수 있다.
(max [1 2 3 4 5 6 7 8 9])
[1 2 3 4 5 6 7 8 9]

(apply max [1 2 3 4 5 6 7 8 9])
9

(max 1 2 3 4 5 6 7 8 9)
9
보이는가 apply를 써서 자료구조를 부시고 개별 인자로 함수에 전달을 하게 된다. 이걸로 into함수를 만들어 보자.
(defn my-into
  [target additions]
  (apply conj target additions))

(my-into [1] [2 3 4])

[clojure-docs]conj



conj

conj는 into랑 비슷하다. 비.슷.해.서. 헷갈릴 것이다.
(conj [] [1])
[[1]]
??? 헷갈릴 수가 없을 것 같다.
(conj [1] [3 4])
[1 [3 4]]
벡터 [1] 안에 벡터 [3 4]가 들어간 것이다. 만약 [1 3 4]가 되게 하고 싶다면 어떻게 해야 할까?
(into [1] [3 4])
[1 3 4]
전에 있던 into를 사용하면 된다. conj와 into로 정의를 할 수도 있다. (그만큼 비슷하다.)
(defn my-conj
  [target & additions]
  (into target additions))

(my-conj [1] [3 5 6])
[1 [3 5 6]]

[clojure-docs] into



into

into는 중요한 집합 함수이다. 배열 함수는 대체로 원래 자료 구조가 아닌 배열을 반환한다. 그런데 원래 배열이나 특정배열로 변환하여 반환하려면 into가 필요하다.
(map identity {:a "AAAA!!!"})
([:a "AAAA!!!"])

(into {} (map identity {:a "AAAA!!!"}))
{:a "AAAA!!!"}
(map identity [:I :MY :ME])
(:I :MY :ME)

(into [] (map identity [:I :MY :ME]))
[:I :MY :ME]
(map identity [:AAA :AAA])
(:AAA :AAA)

[clojure-docs]repeat, repeatedly



repeatedly, repeat

(concat (take 8 (repeat "na")) ["Batman!"])
("na" "na" "na" "na" "na" "na" "na" "na" "Batman!")
repeatly는 와 repeat는 다르다. 아래 내용은 repeat으로 한번 돌려봐라. 생각처럼 안돌아 갈 것이다. repeatedly는 각각 계속 실행시킨다.
(take 3 (repeatedly (fn [] (rand-int 10))))
(3 5 6)

[clojure-docs]sort, sort-by



sort, sort-by

딱 봐도, 정렬인 줄 알겠지?
(sort [5 4 3 2 6 1 3 4 2 6])
(1 2 2 3 3 4 4 5 6 6)
sort-by는 무언가 (다른 거)에 정렬이 되는 것
(sort-by count ["aaa" "bb" "c"])
("c" "bb" "aaa")

[clojure-docs]some



some

some은 처음에 나오는 함수가 참인 경우가 하나라고 있는지 물어보는 것이다.
(some #(> % 5) [1 2 3 4])
nil

(some #(> % 3) [1 2 3 4])
true
여기 나오는 값이 실제 값이 아닌 true인 것을 유의하자. 트릭으로 and를 쓰면 된다. (and가 매크로라서(?) 되는듯 나중에 더 공부하고 적어보기로 하겠다.)

2016년 11월 15일 화요일

[clojure-docs]filter



filter를 쓰면 참인 것만 추려내서 반환한다.
(filter #(< % 3) [1 2 3 4 5 6])
(1 2)
여기서 take-while과 filter의 차이는 무엇일까. take-while은 값이 정렬되어있으면 불필요한 자료를 검사하지 않고 결과 값을 반환한다. (정렬이 되어 있을 때는 take-while이 더 효율적인 듯 싶다.)

[clojure-docs]take-while



take-while

(def food-journal
  [{:month 1 :day 1 :human 5.3 :critter 2.3}
   {:month 1 :day 2 :human 5.1 :critter 2.0}
   {:month 2 :day 1 :human 4.9 :critter 2.1}
   {:month 2 :day 2 :human 5.0 :critter 2.5}
   {:month 3 :day 1 :human 4.2 :critter 3.3}
   {:month 3 :day 2 :human 4.0 :critter 3.8}
   {:month 4 :day 1 :human 3.7 :critter 3.9}
   {:month 4 :day 2 :human 3.7 :critter 3.6}])
take-while을 써서 특정 자료만 얻을 수 있다. 1,2월 자료만 가져온다.
(take-while #(< (:month %) 3) food-journal)
({:month 1, :day 1, :human 5.3, :critter 2.3} 
 {:month 1, :day 2, :human 5.1, :critter 2.0}
 {:month 2, :day 1, :human 4.9, :critter 2.1}
 {:month 2, :day 2, :human 5.0, :critter 2.5})
비슷한 drop-while이라는 것도 기억하자.
(drop-while #(< (:month %) 3) food-journal)
이 둘을 함께 써서 2월과 3월의 자료만 얻을 수 있다.
(take-while #(< (:month %) 4)
  (drop-while #(< (:month %) 2) food-journal))

[clojure-docs]take, drop



take

take는 두개의 인자를 받는다. 일단 한번 보자.
(take 2 [ 1 2 3 4 5])
(1 2)
drop 또한 두개의 인자를 받는다.
(drop 3 [1 2 3 4 5 6 7])
(5 6 7)
둘이 서로 비슷한 함수다.

2016년 11월 14일 월요일

[clojure-docs]reduce



reduce

process each element in a sequence and build a result(배열의 원소를 각각 처리)
(reduce + [1 2 3 4])
10
이 말은 이거와 같다.
(+ (+ 1 2) 3) 4)
끔찍하지 않은가?? 다음은 초기값을 지정하고 reduce를 실행하는 모습
(reduce + 100 [1 2 3 4])

2016년 11월 13일 일요일

[clojure-docs]loop



loop

이것도 말그대로 loop문을 만드는 것이다. 하지만 우리가 생각하는 index를 가지고 for문을 도는 것이 아니라. 재귀를 한다. 한번 어떻게 되는건지 보자.
(loop [x 10]
  (when (> x 0)
    (println x)
    (recur (- x 1))))
10
9
8
7
6
5
4
3
2
1
nil
위의 예제는 x=10이 초기값으로 시작한다. recur는 재귀를 실행한다.

[clojure-docs]zipmap



zipmap

값을 연결해서 맵을 만들어 준다.
(zipmap [:a :b :c :d] [1 2 3 4 5])
{:a 1, :b 2, :c 3, :d 4}
그럼 map이랑 차이는 뭘까? map은 함수를 계속 실행시킨다. 그 값을 리스트로 반환한다.
덧붙여서 다른 질문들을 둘러보자.
zipmap, map vector의 차이를 찾고 있다.
(zipmap [:k1 :k2 :k3] [10 20 40])
=> {:k3 40, :k2 20, :k1 10}

(map vector [1 2 3] [4 5 6] [7 8 9])
=> ([1 4 7] [2 5 8] [3 6 9])
스택오버플로우에서는 그 차이를 이렇게 말한다.
Use (zipmap ...) when you want to directly construct a hashmap from seperate of keys and values. The output is a hashmap.
Use (map vector...) when you are trying to merge multiple sequences, The output is a lazy sequence of vectors.

[clojure-docs]dotimes



dotimes

말그대로 여러번 계속 실행하도록 하는 것.
(dotimes [n 5] (println "n is" n))
n is 0
n is 1
n is 2
n is 3
n is 4
nil

[clojureapi]juxt



juxt

juxtaposition : 병렬, 병치, 나란히 놓기 api doc에 잘 설명되어 있다. juxt 안에 있는 함수들을 나란히 놓는 것이다. ((juxt a b c) x) => [(a x) (b x) (c x)]
((juxt :a :b) {:a 1 :b 3333 :c 3234 :d 234})
[1 3333]
왜 이렇게 나오는 걸까 이유는
[(:a {:a 1 :b 3333 :c 3234 :d 234}) (:b {:a 1 :b 3333 :c 3234 :d 234})]
이렇게 각각 함수(:a :b)를 호출하는 것이다.

[clojureapi]doseq




doseq

body의 내용을 각각 실행시킨다. api에 적혀있는 예제를 보면
(doseq [x [-1 0 1]
        y [1  2 3]] 
  (prn (* x y)))
-1
-2
-3
0
0
0
1
2
3
nil
이렇게 각 벡터를 x,y라 하고 각각 계산한다. 총 값을 9개가 나온다.

[Mathematics for Computer Science][Division Algorithm] 스터디 07

The Division Algorithm

If one number does not evenly divide another, then there is a remainder" left over. More precisely, if you divide n by d, then you get a quotient q and a remainder r.
어떤 수가 나누어지지 않을 때 (즉 소수일 때?) 그 수는 나머지를 가진다. 그리고 몫도 알 수 있다. 이 말은 y = ax + b가 된다는 말.

Theorem 25 (Devision Algorithm)

Let n and d be integers such that d less than 0. Then there exists a unique pair of integers q and r such that n = qd + r and 0 ≤ r  less than d. 위의 y = ax + b와 비슷한 말이다. 여기서 문제는 저 여기서 a와 b의 조합이 단 하나라는 점이다. 어째서 그러한 지 보자. Proof. We must prove that the integers q and r exist and that they are unique.
For existence, we use the well-ordering principle. Fisrt, we show that the equation n = qd + r holds for some r ≥ 0. If n is positive, then the equation holds when q = 0 and r = n. If n is not positive, then the equation holds when q = n and r = n(1-d) ≥ 0. Thus, by well-ordering principle, there must exist a smallest r ≥ 0 such that the equation holds. Furthermore, r mush be less than d; otherwise, b = (q +1)d + (r-d) would be another solution with a smaller nonnegative remainder, contradicting the choice of r.
Well-ordering Principle 자연수의 정렬성 - 공집합이 아닌 모든 자연수 집합의 부분집합은 하나의 최소 정수를 포함한다는 정리 S is subset of T ∀S such that S ⊆ ℕ and S not equals∅,∃a ∈ S such that a ≤ b for all b ∈ S
즉, 최소항이 존재한다는 말 자연수 1 2 3 4 ... (공집합이 아닌 부분집합을 생각하라) 예를 들어 1.5보다 큰 자연수의 집합 -> 최소항 '2'가 존재한다.
Now we show uniqueness. Suppose that there exist two diffent pairs of integers q1, r1 and q2, x2 such that:

n = q1d + r1 (where 0 ≤ r1 less than d)
n = q2d + r2 (where 0 ≤ r2 less than d)

Subtracting the second equation from the first gives:

0 = q1 - q2d + (r1 - r2)
자연수의 정렬성(well-ordering principle)에 의하면 무조건 0보다 크거나 같은 r이 존재한다.(음수건 양수건) 그리고 r은 d보다 작아야 한다. (당연하지 나머지니까) 만약 아니면 값이 엄청 많아진다. 유니크하지 않다는 것! 유니크하다는 것을 말해주기 위해 같은 값에 두개의 조합이 있다고 가정하는 것이다. (바로 위에 만든 것처럼)
The absolute difference between the remainders r1 and r2 must be less than d, since 0 ≤ r1, rless thand. This implies that the absolute value of (q1 - q2)d must also be less than d, which means that q1 - q2 = 0. But then the equation above implies that r1 - r2 = 0 as well. Therefore, the pairs q1, r1 and q2, r2 are actually the same, which is a contradiction. So the quotient and remainder are unique.
나머지의 차는 d보다 작아야 한다.(r1,r2의 조건을 보라) 나머지가 d만큼 차이가 나지 않으니까 (q1 - q2)d 또한 0보다 작아야 한다. 이러면 어쩔 수 없이 저 값은 0 이 된다. 그리고 나머지의 차도 0이 된다. 둘은 같은 값인 것이고, 이것은 모순이 된다.(왜냐하면 처음에 두개의 조합을 가정했다.)

[누구나 쉽게 배우는 클로저] [함수(function)][destructuring] study 10




DESTRUCTURING


DESTRUCTURING은 집합에서 이름에 간단히 값을 매기기 위한 아이디어를 바탕으로 한다.

(defn my-first
  [[first-thing-in-vector]]
  first-thing-in-vector)
(my-first [1 2 3 4 5 6])
1

my-first 안에 들어있는 인자가 벡터로 되어있는 것을 보자. "이 인자는 벡터!"라는 것을 말해주는 것이다. 이 벡터안에 있는 것들을 마음데로 이름 붙이고 또 나머지 매개변수도 쓸 수 있다.

(defn students
  [[first second & others]]
  (print (str "첫 번째 학생: " first))
  (print (str ", 두 번째 학생: " second))
  (print (str ", 나머지 학생: " (clojure.string/join ", " others))))

(students ["Kim" "Min" "Nam" "Hwang" "Ku"])

이번에는 벡터가 아닌 맵으로 해보자. 맵에 있는 내용과 나의 매게변수와 연결을 할 수 있는데 자세한 것은 밑에서 구경해보자.
(defn coordinate
  [{x :x-axis y :y-axis}]
    (println (str "x축: " x))
    (println (str "y축: " y)))
(coordinate {:x-axis 24 :y-axis 44})
더 간결하게
(defn coordinate
  [:keys {x-axis y-axis}]
  (println (str "x축: " x-axis))
  (println (str "y축: " y-axis)))
:as를 사용하여 원래의 맵에 접근할 수 있다.
(defn coordinate
  [:keys [x-axis y-axis] :as args}]
  (println (str "x축: " x-axis))
  (println (str "y축: " y-axis)))

[누구나 쉽게 배우는 클로저] [함수(function)] study 9

클로저 함수 정의하기

조금 더 함수를 정의하는 것에 대해 공부하다. 이번에는 인자의 개수와 무관하게 일을 처리하도록 만들 수 있다. 예를 들자면 전에 보았던 이런 것을 말한다.
(+ 1 2 3 4 5 6 6  23 4 2 3 4 2 34 23 4 235 23 42 35 23 42 34 2342 34 23 4 23 42 3)
=> 3031
이렇게 하는 것
(defn check
  [student]
  (str student " check!"))

(defn attendance-check
  [& students]
  (map check students))

(attendance-check "Kim" "Nam" "Park")
이러면 여러개의 일을 할 수 있다. 간단하지 않은가?

2016년 11월 10일 목요일

[누구나 쉽게 배우는 클로저] [함수(function)] 스터디 8

함수 호출, 매크로 호출, 특수 형식

앞에서 함수 호출하는 법을 보았다(함수 식을 연산자로 하는 식). 이와 다른 두 가지 형태로는 매크로 호출(macro call)특수 형식(special form)이 있다. 일단 다른 이야기보다 함수에 대해 더 다뤄보자.

(defn no-params
  []
  "I take no parameters!")

(defn one-param
  [x]
  (str "I take one paramter: " x))

(defn two-params
  [x y]
  (str "Two parameters! That's nothing! Pah! I will smooth them "
       "together to spite you! " x y))
매개변수가 0인 것, 1개인 것, 2개인 것을 나열했다. 클로저의 함수는 개수 덧쓰기(arity overloading)를 지원한다. 즉, 인자 개수에 따라 서로 다른 함수 몸체가 실행되는 함수를 만들 수 있다는 것이다.
(defn multi-arity
  ;; 3개의 인자와 함수 몸체
  ([first-arg second-arg third-arg]
    (do-things first-arg second-arg third-arg))
  ;; 2개
  ([first-arg second-arg]
    (do-things first-arg second-arg))
  ;; 1
  ([first-arg]
    (do-things first-arg)))
한번 만들어보자.
(defn slap ([name sound]
    (str  name "에게 뺨을 때렸더니? " sound "! 소리가 났다."))
  ([name]
    (str name "에게 뺨을 딱!")))

> (slap "you")
"you에게 뺨을 딱!"
> (slap "you" "BBAK!")
"you에게 뺨을 때렸더니? BBAK!! 소리가 났다."
느낌이 오는가?? 그냥 오버로딩 한다 생각하고 괄호로 만들면 된다.

[누구나 쉽게 배우는 클로저] [함수(function)] 스터디 7


((or + -) 1 2 3)
(or + -)가 +를 반환하기 때문에 이 식의 답은 6이 된다. 다른 예도 보자.
((and (= 1 1) +) 1 2 3)

((first [+ 0]) 1 2 3)
정말 신기 하지 않은가???
(1 2 3 4)

("test" 1 2 3)
java.lang.ClassCastException: java.lang.String cannot be cast to clojure.lang.IFn
이 에러는 함수가 아닌 것을 함수처럼 쓰려고 할 때 나오는 문장이다. 함수를 인자로 취하거나 함수를 반환하는 함수를 고차원함수(higher-order function)라고 부른다.
고차원 함수 기능이 있는 프로그래밍 언어는 일등급 함수(first-class function)를 지원한다고 하는데, 숫자/벡터 같이 익숙한 자료 유형을 다루는 것처럼 함수를 값으로 취급하기 때문이다.< br />
예를들어보자.
(inc 1.1)

(map inc [0 1 2 3])
map함수는 집합의 각원소([0 1 2 3])에 주어진 함수(inc)를 적용하여 새로운 목록을 만든다. 클로저가 일등급 함수를 지원하기 때문에 이를 지원하지 않는 다른 언어에 비해 훨씬 강력한 추상화가 가능하다(고 한다...).

2016년 11월 9일 수요일

[누구나 쉽게 배우는 클로저] [집합(set)] 스터디 6


#{:a :b :c}

이것이 집합인데 집합은 좀 특이하다. 집합은 고유한 값의 모임이다. 클로저는 해시 집합과 정렬된 집합을 갖고 있다고 하는데 여기서는 해시집합을 보도록하자.

(hash-set 1 2)
=> #{1 2}

(conj #{1 2} 2)
=> #{1 2}

고유한 값이기 때문에 더해도 안 더해진다.

(set [3 3 4 2 3])
=> #{2 3 4}

다른 함수들도 알아보자

(contains? #{:a :b} :a)
=> true

(contains? #{:a :b} 3)
=> false

(contains? #{nil} nil)
=> true

또는

(:a #{:a :b})
=> :a


(get #{:a :b} :a)
=> :a




[누구나 쉽게 배우는 클로저] [목록(list)] 스터디 5


'(1 2 3 4)

=> (1 2 3 4)

리스트는 벡터와 다르게 get함수로 얻어올 수 없다. 대신 nth를 쓴다.

(nth '(:a :b :c) 0)
=> :a


그리고 요소를 더할 때는?

(conj '(1 2 3) 4)
=> (4 1 2 3)

여기서 벡터랑 다른 점이 있다. 추가한 4가 맨 처음에 추가 된다는 점이다.

[누구나 쉽게 배우는 클로저] [벡터]스터디 4


[3 2 1]

끝. 이게 벡터다

(get [3 2 1] 0)
=> 3

이것이 무엇을 뜻하는 것 같은가. 그렇다. get 함수로 0번째 위치를 뱉어낸다. [] 이게 싫다면 이렇게 써도 된다.
(vector 3 2 1)
=> [3 2 1]

하지만 결국 [] 안에 들어간다.

(conj [1 2 3] 4)
=> [1 2 3 4]

딱 보아도 conj가 무엇인지 알 수 있지 않은가? 이게 벡터다. 

[javascript patterns][설정 객체 패턴] 스터디 13


설정 객체 패턴

설정 객체 패턴은 좀 더 깨끗한 API를 제공하는 방법이다. 라이브러리나 다른 프로그램에서 사용할 코드를 만들 때 특히 유용하다. 소프트웨어를 개발하고 유지보수하는 과정에서 요구사항이 변경되는 것은 어쩔수 없는 현실이다. 변화하는 요구사항에 우리는 어떻게 코드로 대처해야 할까. addPerson()이라는 함수를 가정해보자. 처음에는 이름과 성만 만들어 사람을 추가하라고 요구를 했다.
function addPerson(first, last) {/*...*/}
갑자기 생일, 성별, 주소 도 저장해야 한다고 한다.(게다가 선택적으로) 선택적으로 저장하는 것을 모르겠고 일단 매개변수를 추가해보자.
function addPerson(first, last, dob, gender, address) {/*...*/} //선택적인 매개변수는 일부러 뒤에 적었다.
함수가 좀 길어졌다. 그런데 username은 필수로 저장해야 한다고 전화가 왔다. 이제 함수를 호출할 때는 필수로 써야 하는 것, 선택적인 매개변수, 그리고 매개변수의 순서... 점점 많아지고 복잡해진다.
addPerson("Younghwan", "Nam", new Date(), null, null, "myID");
많은 수의 매개변수는 참 불편하다. 모든 매개변수를 하나의 객체로 만들어 전달하는 것이 더 낫다. 이 객체를 설정(configuration)을 뜻하는 conf라고 해보자.
var conf = { username: "myID", first: "Bruce", last: "Wayne" };
addPerson(conf);
이 패턴은 함수가 DOM 엘리먼트를 생성할 때, 엘리먼트의 CSS스타일을 지정할 때 유용하다. 엘리먼트와 스타일은 많은 수의 어트리뷰트와 프로퍼티를 가지며 대부분은 선택적인 값이기 때문이다.

2016년 11월 5일 토요일

[Mathematics for Computer Science] 스터디 06

Logical Deductions

Logical Deductions는 논리적 추론이라고 할 수 있는데 여기 중요한 기호들이 나온다.
One fundamental inference rule is modus ponens. This rule says that if P is true and P ⇒ Q is true, then Q is also true. Inference rules are sometimes written in a funny notation.
P
P ⇒ Q
---------------
Q
점선은 원래 실선으로 되어 있어야 한다. 풀어보자면 P가 true이고 P ⇒ Q가 true이면 Q도 true라는 뜻이다. 이것을 modus ponens(논리 긍정식)이라 한다.
Modus ponens is closely related to the proposition (P ∧(P ⇒ Q)) ⇒ Q. Both in some sense say, "if P and P ⇒ Q are true, then Q is true". This proposition is an example of tautology, because it is true for eery setting of P and Q. The difference is that this tautology is a single proposition, whereas modus ponens is an inference rule that allows us to deduce new propositions from old ones. However, if we accept modus ponens then a eneral theorem of logic says that for each tautological implication there is an associated inference rule.
예를들어 ((P ⇒ Q) ∧ (Q ⇒ R)) ⇒ (P ⇒ R) and ((P ⇒ Q) ∧ ¬Q) ⇒ ¬P 둘다 tautologies(동어반복, 항진식)이다. 말로 풀어쓰면 P가 Q이고, Q가 R이라면, P는 R이다. P가 Q이고 Q가 R이 아니라면(false라면) P는 R이 아니다(false다)라는 말과 동일하다.

여기서 ¬이것은 not을 나타낸다.

2016년 11월 4일 금요일

중간리뷰

  공부한 모든 내용을 이곳에 다 적지는 않았지만 나는 지금도 수학공부를 짬내서 하고 있다. 현재 공부 하고 있는 내용은 Number Theory이며 합동(Congruence)에 대해서 공부를 하는 중이다. 이 모든 내용을 적지 못하는 것은 나의 게으름이며, 나의 부족함이다. 하지만 이렇게 부족한 나도 계속 배우려 하고 있는 점을 여러분들을 기억해주기 바란다. 당신들도 공부를 놓지 않기를 바란다.
  사실 요즘 NodeJS를 깨작깨작 가지고 노는 중이다. 자바와 다르게 아직 서툴러서 어떤 생각을 해도 제대로 글이(코딩이) 써지질 않는다. 하지만 역시 자바로 코딩하나 자바스크립트로 코딩을 하나 내가 무엇인가를 구현하려 할 때, 그 방식은 똑같다. 그저 문법만 다를 뿐. 그 근본을 바꾸려면 역시 기본을 바꿔야 하고 틀을 바꿔야 한다고 믿는다.

  사실 수학 공부가 정말 쓸모 없다고 생각이 들기도 하나, 내가 입사하면서 느꼈던 수치를 생각하면서 나는 오늘도 공부를 하려 한다. 항상 할 수 있는 것은 아니지만 그렇다고 아예 손을 놓을 수는 없기에 일주일에 한시간이라도 절대 놓지는 않을 것이다.

[여인의 초상]을 읽고

제임스 헨리의 [여인의 초상]은 한 여인 이사벨 아처의 삶을 그려내었다. 말그대로, 이 장편소설은 한 여인에 대해 적은 것이 아니라, 그리려고 노력하였다. 장면 하나하나를 엮으려 노력하기보다는 한 장면 장면이 그림처럼 수놓아지기를 바라지 않았나 싶다. 처음 이사벨이 나타나서 다른 신사들의 마음을 휘어잡고 있을 때, 신사들을 어디로 튈지 모르는 이사벨의 발걸음과 마음을 잡으려고 그녀의 뒤를 쫓았다. 하지만 이사벨을 자유를 원했고 신사들의 청혼을 거절했다.
  이사벨은 그 시대의 미국인 여인의 초상인 듯 하다. 자유분방함을 원하고 결혼을 구속이라 원하며 결혼으로 인한 신분상승만이 여인의 답이라 생각하지 않으며 항상 생기넘치는 기운을 풍기는 사람. 하지만 이사벨은 결국 결혼을 한다. 정략결혼? 아니다. 아이러니한 것이 자신이 간절히 원하여 결혼을 하게 된다. 그녀를 정말 사랑했던 사람들, 자신들이 사회에 주어진 일들을 충실히 하는 사람들을 거절하고 그녀가 상속받은 돈을 사랑한 사람과 결혼한다. 아주 행복하게...
  그녀는 후회하고 후회한다. 그녀는 이미 족쇄를 찼고, 신사들은 그녀를 보며 더이상 행복한 마음을 가지지 않는다. 왜냐하면 그녀의 생기는 갇혀서 퍼지지 못하고 그녀 자신도 더 이상 행복하지 않기 때문이다. 자유? 그런 것들을 생각할 겨를도 없는 듯 하다.
  그녀를 끝까지 도와준 렐프. 아 정말 가여운 렐프. 이사벨에게 큰 돈을 안겨주고 떠나간 렐프. 그는 어쩌면 자신이 안겨준 큰 돈 때문에 이사벨에게 이런 비극이 왔다고 생각하기까지 한다. 그리고 몇 년지 죽는 렐프를 보며 이사벨은 렐프를 보고, 다시 살기위해 이혼을 한다.
.
.
.
이 글을 한 장, 한 줄거리로 다 표현할 수는 없다. 이 책은 줄거리보다도 그들의 독백, 가끔씩 하는 말 한마디가 어쩌면 책을 전부 표현하기도 한다. 하지만 우리가 알아야 하는 점은 자신을 너무 믿지 말라는 점. 그러기 위해서는 더욱 배워야 한다는 점. 이사벨은 참으로 당돌하고 매력이 넘쳤지만 많이 부족했다. 자신의 논리를 더욱 믿지 말았어야 했지만... 그녀는 자신을 너무 믿었고, 자신을 사랑하는 사람들을 너무 믿지 않았다. 자신은 당연히 사랑받아 마땅했다고 생각했었을까? 그 사랑이 다 없어져서야 슬퍼하는 삶이란...

[javascript patterns][메모이제이션(Memoization) 패턴] 스터디 12


함수프로퍼티 - 메모이제이션(Memoization)패턴

함수는 객체이기 때문에 프로퍼티를 가질 수 있다. 사실 함수는 생성될 때부터 프로퍼티와 메서드를 가지고 있다. 그 예가 length다. length는 함수가 받는 인자의 개수를 값으로 가진다.
function func(a, b, c) {}
console.log(func.length); // 3
언제들지 함수에 사용자 정의 프로퍼티를 추가할 수 있다. 함수에 프로퍼티를 추가하여 결과(반환 값)을 캐시하면 다음 호출 시섲ㅁ에 복잡한 연산을 반복하지 않을 수 있다. 이런 방법을 메모이제이션 패턴이라고 한다.
var myFunc = function(param) {
  if (!myFunc.cache[param]) {
    var result = {};
    //... 비용이 많이 드는 수행 ...
    myFunc.cache[param] = result;
  }
  return myFunc.cache[param];
};

//캐시 저장공간
cache 프로퍼티는 함수로 전달된 param 매개변수를 키로 사용하고 계산의 결과를 값으로 가지는 객체(해시)다. 위 코드의 문제는 myFunc함수가 단 하나의 매개변수를 받는다고 가정하고 있다. 게다가 이 매개변수는 문자열과 같은 원시 데이터 타입이라고 가정한다.
더 많은 매개변수와 복잡한 타입을 갖는다면 어떻게 해야 할까? (직렬화하여 해결한다.)
var myFunc = function() {
  var cachekey = JSON.stringify( Array.prototype.slice.call(arguments)),
      result;

  if (!myunc.cache[cachekey]) {
    result = {};
    //비용이 많이 드는 수행...
    myFunc.cache[cachekey] = result;
  }
};

// 캐시 저장공간
myFunc.cache = {};
직렬화하면 객체를 식별할 수 없게 되는 것을 주의하라. 만약 같은 프로퍼티를 가지는 두 개의 다른 객체를 직렬화하면, 이 두 객체는 같은 캐시 항목을 공유하게 될 것이다.
이 함수를 작성하는 다른 방법으로는 하드코딩 대신 arguments.callee를 사용해 함수를 참조할 수 있다. (하지만 곧 사라질 운명이다. 쓰지 않는 것이 낫다. 명심)
var myFunc = function (param) {
  var f = arguments.callee,
      result;

  if (!f.cache[param]) {
    result = {};
    //...비용이 많이 드는 수행...
    f.cache[param] = result;
  }
  return f.cache[param];
};

// 캐시 저장공간
myFunc.cache = {};
};

[javascript patterns] 스터디 11


즉시 객체 초기화

코드부터 보자.
({
  //여기에 설정 값들을 정의한다.
  maxwidth: 600,
  maxheight: 400,

  //메서드도 정의할 수 있다.
  gimmeMax: function() {
    return this.maxwidth + 'x' + this.maxheight;
  },

  // 초기화
  init: function() {
    console.log(this.gimmeMax());
    //초기화작업실시...
  }
}).init();

초기화 시점의 분기

초기화 시점 분기(로드타임 분기)는 최적화 패턴이다. 브라우저 탐지(또는 기능 탐지)가 전형적인 예다.
//변경 이전
var utils = {
  addListener: function(el, type, fn) {
    if (typeof window.addEventListener === 'function') {
      el.addEventListener(type, fn, false);
    } else if (typeof document.attachEvent === 'function') {
      el.attachEvent('on' + type, fn);
    } else { // 구형의 브라우저
      el['on' + type] = fn;
    }
  },
  removeListener: function(el, type, fn) {
      // 거의 동일한 코드
  }
};
이 코드는 약간 비효율적이다. utils.addListener()나 utils.removeListener()를 호출할 때마다 똑같은 확인 작업을 반복해서 실행한다.
// 변경 이후

// 인터페이스
var utils = { addListener: null, removeListener: null};

// 구현
if (typeof window.addEventListener === 'function') {
  utils.addListener = function(el, type, fn) {
    el.addEventListener(type, fn, false);
  };
  utils.removeListener = function(el, type, fn) {
    el.removeEventListener(type, fn, false);
  };
else if (typeof document.attachEvent === 'function') { // IE
  utils.removeListener = function (el, type, fn) {
    el.detachEvent('on'+type, fn);
  };
} else { // 구형브라우저
  utils.addListener = function (el, type, fn) {
    el['on' + type] = fn;
  };
  utils.removeListener = function (el, type, fn) {
    el['on' + type] = null;
  };
}

[javascript patterns] 스터디 10


즉시 실행 함수의 반환 값

var result = (function () {
  return '리턴';
}());
이렇게 사용하면 된다. 그럼 즉시실행하지 않는 함수와는 무슨 차이일까?
var result = function () {
  return '리턴';
};
이 문법이 더 간단하다. 차이점이라면 result(); 로 해야 값이 나온다는 점. 하지만 혹여 함수가 아니라 '리턴'이라는 값이 나올 것이라는 오해를 할 수도 있다. 그래서 '()'이걸 뒤에 붙이지 않는다면?? 값은 나오지 않는다.
var getResult = {
  message : (function () {
    var who = 'me',
        what = 'call';
    return what + ' ' + who;
  }()),
  getMsg : function () {
    return this.message;
  }
};

o.getMsg();
o.message;
이 둘을 보면서 message와 getMsg의 사용법의 차이를 생각해보자.
즉시 실행 함수 패턴은 폭넓게 사용된다. 전역 변수를 남기지 않고 많은 작업을 할 수 있게 해줄 것이다. 서적에 의하면 이 패턴은 북마클릿(bookmarklet)에서 많이 쓰인단다. 어떤 페이지에서도 실행되고 전역 네임스페이스를 깨끗하게 유지하는 것이 중요하기 때문이란다.
개별 기능을 독자적인 모듈로 감쌀 때도 유용하다.
개별 기능을 독자적인 모듈로 감쌀 수도 있따. 이걸로 기능을 단위별로 정의하는 거다. 이것을 module1이라고 하자
// module1.js에서 정의한 module1
(function () {
  // 모든 module1 코드 ....
}());
이 템플릿을 따라 또 다른 모듈로 코딩할 수 있다. 긜고 실제 사이트에 코드를 올릴 때, 어떤 기능이 사용도리 준비가 되었는지 결정하고 빌드 스크립트를 사용해 해당하는 파일들을 병합하면 된다.