2017년 3월 22일 수요일

[타르튀프]를 읽고

열린책들 세계문학서적 중에 아주 특이한 이름의 책을 보았다. [타르튀프]라는 글인데 이 책이 나를 이끈 이유는 머리말을 읽고 나서였다. 글쓴이 몰리에르는 신에 대한 내용도 과감히 희극의 소재로 사용해왔는데, 권력자들을 소재로 사용할 때부터, 그의 서적이 불온서적이 되며, 무대에 올릴 수 없는 등 갖가지 제약을 받게 된다. 머리말에는 그들에 대한 작가의 절제된 분노를 느낄 수 있는데, 그것은 권력자들을 향한 질타였다.
 

[타르튀프]는 이 책에 실려있는 세 편의 희극 중 하나이다. 아주 옛날에 쓴 희극임에도 호흡이 현대와 맞다. 아주 빠르다 못해 가파른 느낌이 준다.분명 그 당시에는 쉴세 없이 웃다보니 막이 내려오는 느낌이 있었으리라.
권력자들은 자신들의 악행을 비난하는 것은 참지만
놀림감이 되는 것은 참지 못한다.
이 바로 위에 있는 글은 [타르튀프]의 머리말에 나오는 문장 중 하나이다. 희극의 중요성은 웃음 속에 감춰진 무엇이라는 것. 웃음으로 밖에 해소할 수 없는 그 무엇을 아주 잘 다룬 작품이었다. 특히 귀족들의 위선된 행동을 풍자한 [타르튀프]라는 희극은 참으로 많은 생각을 하게 해준다.



권력자에게 칼을 휘두를 수 없지만, 그들을 깍아 내릴 수는 있다.
그들을 저 위에 있지 않으며, 우리와 같은 사람이고, 때론 우리보다 아래 있다. 그들이 가진 권능, 신의 축복은 그들이 대단해서가 아니며, 사실 그들이 가진 권능은 신이 준 것이 아닌 우리의 두려움과 그들의 힘에서 나온다. 그들을 희극으로 놀림감으로 만들어 우리 앞에 세우고 심판하도록 하자.


내가 느낀 감상이다. 하지만 몰리에르는 지속적인 압박에 지쳤는지 [타르튀프]의 마지막 희극 [인간 혐오자]에 그의 안타까움, 외로움이 느껴진다.


[linux] ssh은 되는데 sftp가 안되는 경우

sftp root@123.123.123.123
root@123.123.123.123's password:
subsystem request failed on channel 0
Connection closed

그런데 ssh은 잘 들어가진다면?
뭔가 설정을 잘못되어 있을 수 있다. 일단 이걸 열어보자.
#vi /etc/ssh/sshd_config
그리고 sftp를 찾아보자. /sftp-server로 해당 내용을 검색하니 맨 마지막에 내용이 있다.
없으면 넣어주도록 하자.
#override default of no subsystems
Subsystem    sftp    /usr/libexec/sftp-server
이런게 적혀 있어야 한다. 그런데 왜 안되었을까.
해당 패스에 가보기로 하였다.
#/usr/libexec/openssh/s
sftp-server    ssh-keycat    ssh-keysign    sh-pkcs11-helper
#/usr/libexec/openssh/s
뭔가 특이점이 보이는가? 패스가 틀려 있어서 sftp가 안되었던것!! 어서 바꿔주고 재시작을 해보자.
# service sshd restart
이제 잘 될겁니다.ㅎㅎ

2017년 3월 8일 수요일

[java][junit] private인 메소드는 어떻게 테스트를 해야 하나요?

오늘 JUNIT테스트 케이스를 작성하려고 하는데 이상한 것을 봤습니다.
바로 제가 테스트할 메소드가 JUNIT 테스트 케이스 안에 들어있는 것이었습니다.
상황이 뭐냐하면
다른 누군가가 해당 메소드가 privat으로 되어 있었기 때문에 JUNIT에서 불러 올 수 없었던 것이지요. 그래서 똑같은 메소드를 만들어서 테스트를 했던 것입니다.
문제는 이 테스트가 나중에 쓸모 없어진다는 것같아요.
테스트를 나중에 돌려도 잘된다고 나오겠죠. 버그가 있어도
그러면 JUNIT은 어떻게 테스트를 해야 하는거지?
간접적인 테스트를 하는 것이 방법일 것 같아요. private메소드를 사용하는 public 메소드는 최소한 하나는 있을 것이니 그것을 이용해서 테스트를 하는 것입니다.
하지만 그것으로 부족하다고 느끼시다면?
방법이 있습니다. 리플렉션을 사용하는 방법이죠.
코드를 보겠습니다.
import java.util.List;

public class A {
	private String name;
	public A (String name) { this.name = name; }
	
	private String dosthPrivate(int a, String b, List list) {
	  return "name: " + this.name + 
            ", a: " + a + ", b: " + b + ", List: " + list;
	}
}
현재 위에 있는 dosthPrivate은 실행할 방법이 없습니다.
JUnit으로 테스트를 하려면 어떻게 해야 할까요??
이제 테스트 코드를 보도록 합니다.
public class ATest {
  A a = new A("TEST");
  @Test
  public void test() throws Exception{
  Method method = 
    A.class.getDeclaredMethod("dosthPrivate", int.class, 
                              String.class, List.class);
    method.setAccessible(true);
    String result = String.class.cast(method.invoke
      (a, 1, "BBB", new ArrayList(Arrays.asList(1,2,3,5,8,13,21))));
    assertThat(result, CoreMatchers.is
      ("name: TEST, a: 1, b: BBB, List: [1, 2, 3, 5, 8, 13, 21]"));
  }
}
아주 간단하죠?

아주 간단합니다.

2017년 2월 19일 일요일

[clojure] Udemy 클로저 강의를 듣고

이 언어는 나에게 많은 시련을 준 언어이다.
물론 자바를 처음 배울 때 처럼 아침부터 저녁까지 공부한 것은 아니지만 참으로 나의 머리의 한계를 시험하는 언어였다.
클로저를 처음 배우려고 했던 이유는 폴 그레니엄 때문이었다. 내가 일단 이 사람을 어떻게 접하게 되었는지를 적어야 겠다.
나는 문예창작학과로써 서울에 올라온 이후 항상 서점에 갔다.
삼성동에서 학원을 다닐 때에는 코엑스 지하 1층에 있는 영풍문고를 갔다. 매일매일 저녁을 먹지 않고 혹은 저녁 9시에 학원이 끝났을 때, 나는 영풍문고에서 나의 무지 혹은 나의 미래에 대한 불안감, 거기서 오는 허기짐을 문고에서 채웠다.
아무것도 모르면서 계속 읽었다.
그 중에 [해커와화가]라는 책이 있었다.
제1장을 읽고, 다음장을 읽으려 할 때, 문고가 닫는다는 알림과 음악이 흘러나오기 시작했다. 나는 그 책을 사서 집으로 가져가 전부 읽었다.
그의 주장에는 확신이 있었고, 또 그 확신이 허세가 아니라는 것을 이 책 하나만으로 짐작할 수 있었다.
나는 그의 홈페이지를 들어가보았다. 그는 리스프형 언어 Arc를 소개하고 있었다.
리스프형이 무엇인지 궁금하여 lisp에 대해 찾아보기 시작했다.
그리고 scheme를 한 번 사용해보았다.
common lisp도 한 번 만져보았다. (정말... 만져만 보았다)
내가 클로저를 공부한 이유는 다름이 아니라. 내가 보기에 한국 책이나, 외국 원서나 clojure에 대한 책이 더 많아 보였기 때문이다.
꽤나 많은 책을 보았지만 아직도 clojure에 대해 익숙하지 않다. 내가 일로써 사용하지 않아서 그런 것 같기도 하다.
아직 나는 클로저에서 async에 대해서는 전혀 모른다.(구경만했을뿐...)
병렬프로그래밍이라하면 atom, refer 정도 사용할 뿐일 듯 싶다.
한국 책이던, 외국 책이던 정보가 부족한 것은 참으로 안타까운 듯 싶다. 그래서 사람들이 클로저를 사용하는 듯 싶다.
그나마... 자바와 연결이 되어 있어서, nslookup이라던가. 여러 네트워크 프로그래밍에 자바의 메소드를 사용하는 경우가 있는 것같다.
나는 이제 클로저에서 벽에 부딪힌 느낌이다. 뭐 아는 것도 없는데 벽이라니... 그래서 기초라도 제대로 다지자고 Udemy에 있는 강의를 구매했다.

나름 괜찮았던 것 같다. 하지만 더 많은 정보가 있으면 좋을 텐데... 일단 리스프형 언어에 대해서도 아직 이해가 부족한 상태에서 미지의 세계로 나아가려니 참으로 답답하지 짝이없다.


그래도 고민으로 끝나지않고 계속 나아갈 것이다. 이 길이 망하는 길이라 할지라도
배움은 새로운 곳을 나아가기 위한 것이 아니라
같은 곳에서 새로운 것을 바라보기 위한 것이라 믿으니까.
어느날 다시 되돌아와도...
난 달라져 있으리라

2017년 2월 18일 토요일

[java][byte] 0xff 누구냐 넌!

제목에만 적어놓고 언젠가 적어야지 적어야지 했던 글을 이제야 적는다.
자바를 사용할 때 가끔 0xff를 사용해야 할 때가 있다. 없다고? 음... 그렇다면 당신 대신 누군가 해준 것이니 모른다는 것에 감사하시길...

혹시 unsigned int와 singed int를 아는지? 아아 아주 단순한 문제이니 대답을 해주겠다.
unsigned int : 사인(부호)이 안되어있는 int값
signed int : 사인(부호)이 있는 int값
좀 더 자세히 말하면 부호가 있는 int값과 없는 값 둘로 나뉜다. 그렇다면 자바에서 사용하는 int는 무슨 값일까?

???
모를 수도 있고 알 수도 있다. 비전공자인 나로썬 뭔말인가 싶었다. 하지만 다 정보처리기사에 나오니 걱정하지말라. 누가 물으면 이렇게 말해라.
'그거 정보처리기사에서 다 공부했죠.'
자바에는 int건 byte건 unsigned란 없다. signed만을 (이렇게 해서 설계를 잘했다고 하는 강의도 본 적이 있는데 난 허접이라 잘 모르겠다.) 사용한다. 맞다. 부호가 있는 숫자를 사용한단 말이다. 부호가 없는 int는 사용하지 않는다. 뭐야? 그럼 우리가 알 필요가 없잖아??
유감스럽게도 아니다
왜냐하면 세상은 unsigned int로 이루어진 것들이 꽤나 있기 때문이다. 일단 그렇게 사용하던 코드들이 있고 가장 중요한 것은 이 값은 바이트 타입으로 받았을 때이다.
한 번 바이트 타입으로 127 이상으로 값을 넣어보자.
public static void main(String[] args) {
  byte[] a = new byte[] {127, 0, 0, 1};
  byte[] b = new byte[] {128, 0, 0, 1};
}
a는 되고 b는 안된다. 삶과 죽음은 종이한장 차이라더니, 1의 차이가 프로그램을 아예 실행할 수 없게 만들고 있다.
왜그럴까?
바로 자바는 항상 부호가 있는 숫자이기 때문이다.
바이트는 8비트다. 8비트이면 256개를 표현할 수 있는데, 왜 128이 안된다는 것일까?
잘 생각하자 우리는 부호가 있는 값을 이용한다.
256을 반으로 뚝 잘라라


128 | 128 오!! 되잖아!!! 라고 말 할 줄 알았다. 여기서 한 놈은 1을 빼야한다.
왜? 0을 누군가는 표기해야 하니까.
지금은 그래서 0000 0000 이놈이 0을 표현하게 되는데 이 0이 누구꺼냐는 거다.
결론을 말하면 자바 바이트 타입은 -128 ~ 127 이렇게 표현할 수 있다. 그러니 128은 표현할 수 없는 존재가 되는 것이다.
public static void main(String[] args) {
  byte[] b = new byte[] {(byte)128 , 0, 0, 1};
  System.out.println( (byte) 128 );
}
이거 마이너스가 뜬다. 왜냐하면, 128은 int다. 그걸 바이트로 내가 지금 강제로 형변환을 했다. 128은 2의 7승이다. 그 말은 1000 0000 이다.

일단 맨 앞에 1이 있으면 부호가 음수이다.

public static void main(String[] args) {
  byte[] b = new byte[] {(byte)128 , 0, 0, 1};
  System.out.println( (byte) 128 );
  System.out.println((byte) 128 & 0xff);
}
바로 우리가 알아봐야 할 0xff 누구냐넌! 이놈은 이렇게 생겼다. 쟤는 16진수라는 거다.
잠깐 나가지말고 들어보라. 정말 별거 아니니까!!!
0x는 16진수 앞에 붙는 기호라고 하고.
f는 15을 뜻한다.
f가 두개다. 이것 이런 말이다. 15*16^1 + 15*16^0 이거 한번 계산기를 돌려보자.
System.out.println(15*16 + 15*1);
이건 255가 나온다. 255? 어디서 많이 들어 본 것 같지 않은지? 맞다. 우리 네트워크 설정할 때 많이 사용한다. 바로 그 때!!!! 사용되고 있을 지도 모르는 놈이 0xff이다.

여튼 이놈을 이용해서 &(and)연산을 하면 부호가 없는 없는 그냥 숫자가 나올 것이다. (왜?)
잘 생각해보자. 255는 일단 부호가 있는 숫자에서 255라는 숫자가 나온것이다.
그러면 잘 생각해보자.
기호가 없는 255는 1111 1111 이다. 기호가 있는 255는? 무조건 앞이 0이다. 게다가 255는 int라니까? 부호가 있는 32비트다. 32비트!!!
0000 0000 0000 0000 0000 0000 1111 1111
0xff의 정체이다. 자 그런데 어떻게 저 (byte) 128 & 0xff 가 어떻게 되는거지?
자!! 이제 얼마 안남았다.
1111 1111 1111 1111 1111 1111 1111 1111 1000 0000
0000 0000 0000 0000 0000 0000 0000 0000 1111 1111 (and) 연산 실시
----------------------------------
0000 0000 0000 0000 0000 0000 0000 0000 1000 0000
이러면 이제, 부호가 마이너스가 아니라! 부호가 플러스인 128라는 숫자가 된다.
휴... 금방 끝날 줄 알았는데... 하... 힘들었다.


이 글이 정말 서툴지만 누군가에게는 많은 정보가 되길 바랍니다. 그리고 잘못 적은 내용을 지적해주신 분께 감사의 뜻을 전합니다. ^^

2017년 1월 26일 목요일

[clojure] 클로저 소개글

사내 블로그를 적어야 할 일이 있어서(할당량...) 무엇을 적을 까 하다가
클로저에 대해 한 번 써보았다.
좀 약파는 글이기는 한데 재미있었다.
http://blog.naver.com/andwise/220920969200

2017년 1월 22일 일요일

[clojure][design pattern] 상태패턴 , 비지터 패턴


clojure design pattern


출처::http://clojure.or.kr/docs/clojure-and-gof-design-patterns.html#command

3. 상태패턴

유료/무료 사용자 차이, 잔액 계산, 유료 전환

JAVA 
1.두개의상태를 enum으로 만든다.
public enum UserState {
  SUBSCRIPTION(Integer.MAX_VALUE), NO_SUBSCRIPTION(10);

  private int newsLimit; 
 
  UserState(int newsLimit) { this.newsLimit = newsLimit; }
  public int getNewsLimit() { return newsLimit; }
}
2. 유저를 만든다.
public class User {
  private int money = 0;
  private UserState state = UserState.NO_SUBSCRIPTION;
  private final static int SUBSCRIPTION_COST = 30;

  public List newsFeed() { // enum안에 들어있는 리미트 값으로 보여준다.
    return DB.getNews(state.getNewsLimit());
  }

  public void pay(int money) { //돈을 넣어서 잔액을 지불하고 임계점을 넘으면 유료회원이 된다.
    this.money += money;
    if (state == UserState.NO_SUBSCRIPTION
        && this.money >= SUBSCRIPTION_COST) {
      // buy subscription
      state = UserState.SUBSCRIPTION;
      this.money -= SUBSCRIPTION_COST;
    }
  }
}
CLOJURE multimethod
 
(defmulti news-feed :user-state)

(defmethod news-feed :subscription [user]
  (db/news-feed))

(defmethod news-feed :no-subscription [user]
  (take 10 (db/news-feed))) 
** defmulti는 무엇을 플래그로 멀티메소드를 만들 것인가. (:user-state으로 분기한다. 

(def user (atom {:name "Jackie Brown"
                 :balance 0
                 :user-state :no-subscription}))

(def ^:const SUBSCRIPTION_COST 30)

(defn pay [user amount]
  (swap! user update-in [:balance] + amount)
  (when (and (>= (:balance @user) SUBSCRIPTION_COST)
             (= :no-subscription (:user-state @user)))
    (swap! user assoc :user-state :subscription)
    (swap! user update-in [:balance] - SUBSCRIPTION_COST)))

(news-feed @user) ;; top 10
(pay user 10)
(news-feed @user) ;; top 10
(pay user 25)
(news-feed @user) ;; all news

 4. 방문자 패턴 (Visitor pattern);
public abstract class Item{ abstract void accept(Visitor v); }

class Message extends Item { void accept(Visitor v) { v.visit(this);} }
class Activity extends Item  { void accept(Visitor v) { v.visit(this);} }
// 비지터
public interface visitor {
  void visit(Activity a);
  void visit(Message m);
}

class PDFVisitor implements Visitor {
  public void visit(Activity a) { System.out.println("PDFExporter.export(a) - Activity");
  public void visit(Message m) { System.out.println("PDFExporter.export(a) - Message");
}
class ExcelVisitor implements Visitor {
  public void visit(Activity a) { System.out.println("ExcelExporter.export(a) - Activity");
  public void visit(Message m) { System.out.println("ExcelExporter.export(a) - Message");
}
main {
  Item i = new Message();
  Visitor v = new PDFVisitor();
  i.accept(v);
}

더블디스패치패턴이 생겨난 이유는(추측컨데) 인자 타입체크를 하지 않기 때문이다. 예를들어
(비지터 패턴을 사용하지 않는 경우 가정 출처링크 참고)
Item i = new Message();
i.accept()를 실행하면 그것이 Activity인지 Message인지 알 필요가 없다. 왜냐하면 이놈은 타입체크가 이루어지기 때문이다. 하지만 아래 놈은 다르다.
Format f = new PDF(); //여기서 Format은 PDF,EXCEL,GIF를 모두 다루는 놈이라 가정하자.
i.accept(f)
될거라 생각하지 말자.
Format f는 인자로 들어와서 타입체크가 되지 않았다. (인자는 타입체크를 하지 않는다는 것이 중요하다.) 그래서 더블디스패치로 이중 타입체크를 하는 것이다. 하는 방법은 아주 단순하다.
i.apply(f); 
// 만약 이런 메소드를 실행하려 하는데 i는 타입체크가 되었고 f는 인자이기 때문에 타입체크가 안되있다면 이 메소드를 바로 실행하는 것이 아니다.
f.apply(i); // 이렇게 바꿔서 f도 타입체크를 하도록 하는 것이다. 그러면 두번 타입체크가 되는 것이다.
어쨋든 Visitor패턴으로 잘 만들었다.

clojure

(defmulti export
  (fn [item format] [(:type item) format]))
{:type :message :content "Say what again!"}
{:type :message, :content "Say what again!"}
{:type :activity :content "Quoting Ezekiel 25:17"}
{:type :activity, :content "Quoting Ezekiel 25:17"}

(defmethod export [:activity :pdf] [item format]
 (println "exporter/activity->pdf" item))

(defmethod export [:activity :xml] [item format]
  (println "exporter/activity->xml" item))
(defmethod export [:message :pdf] [item format]
  (println "exporter/message->pdf" item))
(defmethod export [:message :xml] [item format]
  (println "exporter/message->xml" item))

(defmethod export :default [item format]
  (throw (IllegalArgumentException. "not supported")))
===============================================
(export {:type :message } :xml)
exporter/message->xml {:type :message}
nil
user=> (export {:type :message } :pdf)
exporter/message->pdf {:type :message}
===============================================
(하지만 :pdf:xml 사이에는 아무런 상하 관계(hierarchy)가 존재하지 않네요. 단순히 키워드일 뿐이잖아요?)
hierarchy만들기
(derive ::pdf ::format)
(derive ::xml ::format)
(isa? ::xml ::format)
(isa? ::pdf ::format)

(defmethod export [:message ::pdf] [item format] (println ":message ::pdf" item))
(defmethod export [:message ::format] [item format] (println ":message ::FORMAT!!!!" item))

(export {:type :message :content "SAYHIHIHIHI"} ::pdf)
:message ::pdf {:type :message, :content SAYHIHIHIHI}
nil
user=> (export {:type :message :content "???????????"} ::xml)
:message ::FORMAT!!!! {:type :message, :content ???????????}
nil

::xml을 구현하지도 않았는데 만들어졌다. FORMAT으로 거슬러 올라가서 일이 실행된것!!

** 더블디스페치를 지원하면 비지터패턴은 의미가 없다.




[clojure][design pattern] 클로저 디자인패턴 - 전략패턴

clojure design pattern
출처::http://clojure.or.kr/docs/clojure-and-gof-design-patterns.html#command

2. 전략패턴(Strategy Pattern)

이름순으로 정렬(단, 유료고객은 먼저)

(def users [{:subscription true :name "Y"} {:subscription true :name "Z"} {:subscription false :name "Z"}])

(sort (comparator (fn [u1 u2]
                    (cond
                      (= (:subscription u1) (:subscription u2))
                      (neg? (compare (:name u1) (:name u2)))

                      (:subscription u1)
                      true

                      :else
                      false)))
      users)
위 소스는 comparator를 만들고 하는 것이 아주 비슷하다.
아래 소스를 봐보자.
(sort-by (juxt (complement :subscription) :name) users) ;; forward sort
(sort-by (juxt :subscription :name) #(compare %2 %1) users) ;; reverse sort
워워 하나씩 보자.
(sort-by count ["aaa" "bb" "c"])

("c" "bb" "aaa")
juxt 이녀석은 뭘까? (juxtaposition : 병렬, 병치)
((juxt a b c) x) == [(a x) (b x) (c x)]
(for [user users]
  ((juxt :subscription :name) user))
;; ([true "Y"] [true "Z"] [false "Z"])


(for [user users]
  ((juxt (complement :subscription) :name) user))
;; ([false "Y"] [false "Z"] [true "Z"])

complement (보수 말하는건가) : 함수를 받아서 true/false의 반대값을 내보냄
(def odd?? (complement even?))
(odd?? 3)
true 
이걸 먼저 알아보자
(sort-by (juxt (complement :subscription) :name) users) ;; forward sort
user=> ((complement :subscription ) {:subscription "HI"})
false
user=> ((complement :a ) {:b "HI"})
true

두 줄로 만들어지는 것이 신기하다. juxt는 엄청난 함수 인 것 같다. 나중에 쓸일이 많을 것 같다.

컴파일 00

컴파일 과정
1. 구문 해석
2. 의미 해석
3. 중간 표현의 생성
4. 코드 생성

1. 구문 해석
소스 코드의 해석을 파스(Parse) 또는 구문해석(syntax analyzing)이라고 한다. 또한 소스 코드를 파스하는 프로그램 모듈을 파서(parser) 혹은 구문 해석시(syntax analyzer)라 한다. 그러면'컴퓨터가 이해하기 쉬운 형식'은 어떤 것일까. 그것은 구문 트리(syntax tree)라고 하는 형식이다. 구문 트리는 이름 그대로 트리 구조로 소스 코드의 문법 구조를 그대로 옮겨 놓은 구조이다.
2. 의미 해석
소스 코드를 Parse해서 구문 트리가 만들어졌으면, 다음에는 구문 트리를 해석해서 필요 없는 부분을 없애기도 하고 정보를 추가하기도 하여 추상 구문 트리(AST, abstract syntax tree) 데이터 구조를 만든다. 이 처리를 의미 해석(semantic analysis)이라 한다.
- 어떤 변수가 로컬 변수인지 글로번 변수인지 구별하기
- 변수 선언과 참조를 연결 짓기
- 변수나 식의 타입을 체크하기
- 변수를 참조하기 전에 초기화하고 있는지 조사하기
- 리턴 값이 있는 함수가 값을 제대로 반환하고 있는 체크하기
3. 중간 표현 생성
추상 구문 트리가 생기면, 다음에는 컴파일러 내부에서만 사용되는 중간 표현(IR, intermediate representation)구조로 추상 구문 트리를 변환한다. 일부러 중간 표현을 생성하는 가장 큰 이유는 여러 종류의 프로그래밍 언어나 기계어에 대응하기 위해서다.
예를들어 CPU에 따라 다른 컴파일러가 필요하다. (중간 표현이 없다면) 그러니 상황에 따라 모든 컴파일러를 만들어야 한다면 엄청난 수의 컴파일러가 필요하다. 그러니 만약 모든 프로그래밍 언어가 공통의 중간 표현으로 변환하면 1개의 언어, 1개의 CPU에 대응하는 코드는 각각 1개만 있으면 된다. 그래서 여러 종류의 언어나 CPU에 대응하는 컴파일러는 중간 표현을 사용하는 것이 좋다. 예를 들면 GCC는 RTL(register transfer language)이라는 중간표현을 사용한다.
4. 코드 생성
마지막으로 중간 표현을 어셈블리 언어로 변환한다. 이 단계를 코드 생성(code generation)이라고 한다. 코드를 생성하는 프고그램 모듈이 코드 제너레이터(code generator)이다. 코드 생성 포인트는 프로그래밍 언어와 어셈블리 언어의 차이를 얼마나 줄일 수 있는가 하는 점이다.
5. 최적화
실제 컴파일러에는 코드를 최적화(optimization)하는 단계까 포함된다.

[clojure]nil 체크

nil 과 false를 제외한 모든 것이 반복문이나 조건문에서 true가 된다.

user=> (if nil true false)
false
user=> (if false true false)
false
user=> (if -1 true false)
true
user=> (if 0 true false)
true
user=> (if "false" true false)
true
하지만 비어있는 컬렉션컬렉션은?
user=> (if [] true false)
true
이럴수가. 하지만 이렇게 하면 된다.
user=> (if (not (empty? [])) true false)
false
이게 뭔고생인가. Joy Of Clojure에서는 다른 방법을 제시한다. 바로 (seq s)이다.
user=> (defn print-seq [s]
  #_=>   (when (seq s)
  #_=>     (prn (first s))
  #_=>     (recur (rest s))))
#'user/print-seq
user=> (print-seq [])
nil

여기서는 rest를 쓰고 next를 쓰지 말라고 하는데 왜인지 한번 보자.
user=> (defn my-seq [s]
  #_=>   (when (seq s)
  #_=>     (prn (first s))
  #_=>     (recur (next s))))
#'user/my-seq
user=> (my-seq [])
nil

음... 이게 문제는 아닌 것같다.
user=> (next [])
nil
user=> (rest [])
()
이게 문제인 것 같다.
rest는 시퀀스가 비어있는지 아니던지 nil를 리턴하지는 않는다.
next는 바로 nil을 리턴한다.
우리는 각 반복 시점마다 (seq s)를 쓴다 그러니 시퀀스를 다루는 rest를 넣는게 더 조합이 잘되있다고 보는 것이다. (nil이 나오지 않게 하려 하는 점은 좋은 생각이다.)

** 여담으로 컬렉션을 순회할 때는 재귀보다는 doseq를 사용하는 편이낫다고 한다. 다만 doseq를 사용하면 위철머 살펴 보는 것은 힘들다. 클로저에서 do로 시작하는 구문 (doseq, dotimes, do 등)은 부수 효과를 일으키기 위해 사용하기 때문에 보통 결과로 nil을 리턴한다.

ORA-01722: 수치가 부적합합니다 [해결]

ORA-01722: 수치가 부적합합니다
01722. 00000 -  "invalid number"
*Cause:    The specified number was invalid.
*Action:   Specify a valid number.

이 에러는 딱 봐도 숫자가 문제가 있다는 에러인데, 확인하고 고쳐달라는 부탁(?) 오더(?)를 받았다.
그런데 아무리 봐도 뭐가 문제 인지 알 수가 없었다. 왜냐하면

//가상의 테이블
======================================
SELECT EMAIL, MOBILE, MEMBER_NO FROM INFO Where EMAIL is not null AND USER_CODE=00000000 AND MOD(USER_NO,3)=1;
======================================
이건 잘 나오는데
======================================
SELECT count(*) FROM ( SELECT EMAIL, MOBILE, MEMBER_NO FROM INFO Where EMAIL is not null AND USER_CODE=00000000 AND MOD(USER_NO,3)=1 )
======================================
이건 안되는 것이다.

혹시해서
DESCRIBE를 이용해서 테이블을 확인했다. USER_NO가 VARCHAR임을 확인하고
TO_NUMBER를 한번 붙여보기로 했다.
======================================
SELECT count(*) FROM ( SELECT EMAIL, MOBILE, MEMBER_NO FROM INFO Where EMAIL is not null AND USER_CODE=00000000 AND MOD(TO_NUMBER(USER_NO),3)=1 )
======================================
그래도 안된다
혹시해서 한 번더!
======================================
 SELECT count(*) FROM ( SELECT EMAIL, MOBILE, MEMBER_NO FROM INFO Where EMAIL is not null AND USER_CODE=00000000 AND TO_NUMBER(MOD(TO_NUMBER(USER_NO),3)) =1 )
======================================
된다. 오라클에 대해 잘 몰라서 어떤 일이 일어났는지는 잘 모르겠다. VARCHAR에서 TO_NUMBER 했으면 숫자가 된 것이 아닌가? 그러면 count(*)는 안되고 전부 찍는 건 되는 거지? 좀 더 알아봐야할 것 같다.

clojure 파일 쓰기 (lazy sequence를 만난 순간)

100만개의 가짜 이메일을 만들어야 할 일이 생겼따.
그래서 숫자를 이용해서
0@test.com
1@test.com
2@test.com
3@test.com
4@test.com
.
.
.
1000000@test.com
이렇게 만드는 것인데 클로저로 하니까 아무리 해도 안되서, 결국 자바로 만들었다.
나는 정말 많이 부족한가보다... 라고 생각하고 있던 찰나
일이 끝나고 저녁 먹으면서 한번 REPL을 켜서 테스트해봤다.

(spit "/Users/tom/a.txt" 
  (clojure.string/join "\n" 
    (flatten (for [x (range 0 1000000)] 
                (conj '() (str x "@test.com"))))))
잘된다.
클로저를 하지 말아야 하나...

해당내용을 구글 클로저 그룹스에 물어봤는데 다들 멋지게 풀어 선보이기 시작했다.

(spit "a.txt" (clojure.string/join "\n" 
                (for [x (range 1000000)]

                  (str x "@test.com, " x))))

(spit "a.csv" (with-out-str
                (dotimes [n 1e6]
                  (println (str n "...@test.com, " n))))) 
거기서 나온 조언은 lazy시퀀스가 반환될 때, dall함수나 dorun함수를 이용해서 강제로 실행시켜야 한다는 것이다.
ex)

(def foo (map println [1 2 3]))
#'user/foo
(def foo (doall (map println [1 2 3])))
1
2
3
#'user/foo
lazy sequence에 대한 개념이 부족했었다. 정말... 아직 멀었다.

[clojure][macro] 매크로사용하기 00

Code is Data 라는 말은 코드 자체가 프로그래밍 언어의 자료구조가 된다는 말이다. 클로저 매타프로그래밍(macro)를 하게 되면 우리는 expression level에서 생각하게 된다 rather than at the textual level.

코드 자체가 데이타(자료구조)이기 때문에 이것을 맘대로 바꿀 수 있다.

어쨋든 이게 뭐라는 거야
제대로 알아보자. (REPL을 예로들자)

REPL : Read-Eval-Print loop

Read : 문자단위표시방식 (character-based representation, typically an input stream) 을 받아서 클로저 자료구조로 변환한다. 그래서 Read phase(읽기상태)의 아웃풋은 data(데이타)이다. 이 데이터는 두번째 상태에서 평가된다. (데이터로!)

EVEL : 어떻게 EVAL에서 code-as-data에서 data-as-code로 변할까 (자료구조안에 있는 코드들이 코드로 만들어진 데이터)

read는 표현식(매크로가 잘 작동하는)을 작성 할 때(building the expression) 편한다. 다음의 인풋과 아웃풋을 보자. (어떻게 이게 동작하는지 잘보자.)

첫 매크로는 바로 머리에 때려박아주기 적절한 예시가 될것(ll give you enough to dive headfirst into your first macro.)

실제 클로저의 read 함수는 stream을 사용한다.(consume stream) 이런 행위는 셋업하는데 많은 짓을 해야 할지도 모른다.(verbose to set up.)

이 예제의 목적에 따라. read의 형제격인 read-string을 받겠다. (stream 대신 strings를 받는 것) 
 =================================================
(read-string "(+ 1 2 3 4 5)") 
;==> (+ 1 2 3 4 5)
(class (read-string "(+ 1 2 3 4 5)"))
;=> clojure.lang.PersistentList

 =================================================

여기 이 리스트가 우리가 지금까지 이야기 했던 데이터의 조각이다.
이건 클로저 리스트다. 그리고 아직까지는 클로저 코드다.  (Code as Data)
readstring에서 돌아온 값은 평가될 준비가 되어있다.
이 리스트를 평가할 때, 그 표현식의 값을 알 수 있을 것이라 기대한다.

=================================================
(eval (read-string "(+ 1 2 3 4 5)"))
;=> 15
(class (eval (read-string "(+ 1 2 3 4 5)")))
;=> java.lang.Long
(+ 1 2 3 4 5)
;=> 15
=================================================
이게 REPL에서 실제로 일어나고 있는 일이다. 아니면 완전체 클로저(full-blown clojure project)를 실행할때에도 실제 일어난다. 코드는 자료구조(data structure)로 읽어지고(be read into, 저장되고) 그러고 나서 평가된다(eval). 이 두 스텝(read, evaluate)을 놓고 보았을 때,
read와 eval 사이에 코드자신이 평가되기 위해 자기자신을 끼워넣는 것(꼽사리로 들어가는 것)을 어렵지 않을 것이다.


예를들어 we could replace addition with multiplication:
=================================================


(let [expression (read-string "(+ 1 2 3 4 5)")
  (cons (read-string "*")  ;; 꼽사리로 들어가는 현장
        (rest expression)))
;=> (* 1 2 3 4 5)

(eval *1) ;; *1 holds the result of the previous REPL evaluation
;=> 120
=================================================
이게 무슨 뜻이나면 read-string에다가 일단 곱하기(*)를 넣고 그 다음에는 더하기(+)를 제외한 값(rest)를 가져와서 합친것이다.

물론, 만약 새롱누 리스트를 평가(eval)한다면, 원래 결과와는 전혀 다른 내용이 나올 것이다. 이전에 나온 예시도 나쁘지 않지만 단순히 문자열값을 읽는 것보다는 제대로 표현식을 지어보자.
냅다 이런 "(+ 1 2 3 4 5)" 스트링을 만드는 것은 이상하단 말이야.
하지만 이런 형태의 리스트를 생성하고 싶다면 단순히 (+ 1 2 3 4 5) 이렇게 타입한다고 될 일이 아니다. 왜냐하면 이것 실제로 표현식으로 평가될 것이기 때문이다.
=================================================
(let [expression (+ 1 2 3 4 5)] ;; expression is bound to 15
  (cons
    (read-string "*") ;; *
      (rest expression))) ;; (rest 15)
; IllegalArgumentException Don't know how to create ISeq from: java.lang.Long
; clojure.lang.RT.seqFrom (RT.java:505)
=================================================
보아라 (+ 1 2 3 4 5)가 바로 그냥 15로 평가 되는 것이다. 왜냐하면 (실제로 표현식으로 평가되기 때문에!)

그래서 다른 솔루션이 필요하다. 하나는 실행을 억제하는 거다. 운좋게도 클로저에는 quote라는 동사(verb, 이 verb에 유념하라 function이 아니다)가 똑같은 일을 한다.
=================================================
(let [expression (quote (+ 1 2 3 4 5))]
  (cons (quote *)
        (rest expression)))
;=> (* 1 2 3 4 5)

(eval (let [expression (quote (+ 1 2 3 4 5))]
  (cons (quote *)
        (rest expression))))
;= 120
=================================================

quote verb는 사실 클로저의 특별한 형태(Clojure special form)이며 함수가 아니다.  우리는 이 verbs를 (공식적인 의미는 아님) 함수,매크로 그리고 special forms의 결합체라고 생각하면 된다.

리스트(Lists) 또한 verb 위치로 보여질 수 있는데 평가(eval)될 때는 함수위치로 축소되어야 한다.

함수(function)만이 아규먼트(여기서 아규먼트란 평가될 모~든 데이터를 말하는 듯 하다)를 제대로 평가한다. (컨트롤흐름을 코드(구현한 verbs)로 패스하기전에)
  * Only functions uniformly evaluate their arguments before passing control to the code that implements the verb.


=================================================
(defn print-with-asterisks [printable-argument]
  (print "*****")
  (print printable-argument)
  (println "*****"))

(print-with-asterisks "hi")
; *****hi*****
;= nil
=================================================
verb - 어떻게 정의하나? - 언제 아규먼트가 평가되나?
Functions - defn - Before executing the body
Macro -defmacro - Depends on macro; possibly multiple times or never.
Special form - We can’t! They’re only defined by the language. - Depends on special form; possibly multiple times or never.

자 위에 나온 print-with-asterisks같은 걸 만들 때는 굳이 언제 아규먼트가 평가(timing of the argument evaluation)되는지 알필요가 없다.

하지만 만약! 표현식을 아규먼트로 쓴다면! 그 해당 함수(print-with-asterisks)가 평가되기 전에 평가된다. (???)
 =================================================
(print-with-asterisks
  (do (println "in argument expression")
  "hi"))
=================================================
잘보라 사용하기 전에 이미 김이 다 빠져나간거다.
Macros and speical forms, 는 이 룰에서 자유롭다. 그리고 어떤 순서에서 정의한 거든 아규먼트를 평가할 것이다. (아니면 이상하게 작동해서 망하던가...)  이게 함수와 매크로의 큰 차이란다.

quote expression (quote ...)안에 있는 코드는 평가되지 않는다. 그리고 아주 단순한 토큰들도 가능하다. (심볼, 리스트, 벡터.. 모두)
=================================================
(quote 1)
;= 1
(quote "hello")
;= "hello"
(quote :kthx)
;= :kthx
(quote kthx)
;= kthx
=================================================
근데 귀찮게 항상 QUOTE을써야 하나? 아니다 더 좋은게 있다. 
Reader macro라는 것이다. 이건 우리가 만들 수 있는게 아니다. 언어딴에서 만들어진거라 한다.
=================================================

'(+ 1 2 3 4 5)
;= (+ 1 2 3 4 5)
'map
;= map
user.core=> map
#object[clojure.core$map 0x589a6fa "clojure.core$map@589a6fa"]
user.core= 'map
map
=================================================
오... 확실히 먼가 다르다.
=================================================
(let [expression '(+ 1 2 3 4 5)]
  (cons '* (rest expression)))
;= (* 1 2 3 4 5)
=================================================