좋은 Emacs 및 Elisp tutorial

2월 3rd, 2010 No comments »

emacs에 관한 좋은  사이트가 있어서 링크해둔다.

http://xahlee.org/emacs/emacs.html

http://xahlee.org/emacs/elisp.html

Linux tcp keep alive

12월 9th, 2009 No comments »

ssh는 keepalive 기능이 들어있지만 telnet에는 없어서 무척 짜증이 났는데 tcp의 keep alive를 이용하면 된다.

http://www.dslreports.com/faq/7792

The TCP KeepAlive value is stored in the “proc” filesystem (actually a virtual filesystem maintained by the kernel) under this path:

/proc/sys/net/ipv4/tcp_keepalive_time

The default just happens to be 7200 seconds (same as the BEFSR41 timeout). To defeat NAT it must be something smaller than that, like 1800. Setting it to a really small value like 60 is frowned upon as a bad network administration practice, especially if you are running a server.

So to change it all you need to do is this:

echo “1800″ > /proc/sys/net/ipv4/tcp_keepalive_time

You have to put this in a startup file like “rc.local” to make it permanent.

Beautiful Code « Programming Praxis

9월 14th, 2009 No comments »

Beautiful Code « Programming Praxis.

  1. let match_re re text =
  2.  let len = String.length in
  3.  let get = String.get in
  4.  let remain str o = String.sub str o ((len str)-o) in
  5.  let next_ch ch o_re =
  6.   if len re > (o_re+1) then
  7.    if get re (o_re+1) = ch then true
  8.    else false
  9.   else false
  10.  in
  11.  let curr_ch ch o_re =
  12.   if len re > o_re then
  13.    if get re o_re = ch then true
  14.    else false
  15.   else false
  16.  in
  17.  let rec match_re_star c o_re o_text =
  18.   (* Printf.printf "match_re_star c:%c re:%s text:%s\n" c (remain re o_re) (remain text o_text); *)
  19.   if match_re_here o_re o_text then true
  20.   else if len text != o_text && ((get text o_text) = c || c = '.') then
  21.    match_re_star c o_re (o_text+1)
  22.   else
  23.    false
  24.  and match_re_here o_re o_text =
  25.   (* Printf.printf "match_re_here re:%s text:%s\n" (remain re o_re) (remain text o_text); *)
  26.   if len re = o_re then true
  27.   else if next_ch '*' o_re then
  28.    match_re_star (get re o_re) (o_re+2) o_text
  29.   else if get re o_re = '$' && len re = o_re+1 then
  30.    len text = o_text
  31.   else if len text != o_text && (get re o_re = '.' || get re o_re = get text o_text) then
  32.    match_re_here (o_re+1) (o_text+1)
  33.   else
  34.    false
  35.  and match_re_main o_re o_text =
  36.   (* Printf.printf "match_re_main re:%s text:%s\n" (remain re o_re) (remain text o_text); *)
  37.   if match_re_here o_re o_text then true
  38.   else if len text = o_text then false
  39.   else match_re_main o_re (o_text+1)
  40.  in
  41.  if curr_ch '^' 0 then
  42.   match_re_here 1 0
  43.  else match_re_main 0 0
  44.  
  45. let match_re_test () =
  46.   assert ((match_re "a" "a")=true);
  47.   assert ((match_re "a" "b")=false);
  48.   assert ((match_re "a" "ab")=true);
  49.   assert ((match_re "a" "ba")=true);
  50.   assert ((match_re "ab" "ab")=true);
  51.   assert ((match_re "ab" "ba")=false);
  52.   assert ((match_re "ab" "xab")=true);
  53.   assert ((match_re "ab" "aab")=true);
  54.   assert ((match_re "a.c" "ac")=false);
  55.   assert ((match_re "a.c" "abc")=true);
  56.   assert ((match_re "a.c" "xac")=false);
  57.   assert ((match_re "a.c" "xabcx")=true);
  58.   assert ((match_re "^ab" "ab")=true);
  59.   assert ((match_re "^ab" "ba")=false);
  60.   assert ((match_re "^ab" "aab")=false);
  61.   assert ((match_re "^ab" "abc")=true);
  62.   assert ((match_re "ab$" "ab")=true);
  63.   assert ((match_re "ab$" "ba")=false);
  64.   assert ((match_re "ab$" "aab")=true);
  65.   assert ((match_re "ab$" "abc")=false);
  66.   assert ((match_re "^ab$" "ab")=true);
  67.   assert ((match_re "^ab$" "ba")=false);
  68.   assert ((match_re "^ab$" "abc")=false);
  69.   assert ((match_re "^ab$" "aba")=false);
  70.   assert ((match_re "a.*c" "ac")=true);
  71.   assert ((match_re "a.*c" "abc")=true);
  72.   assert ((match_re "a.*c" "abbc")=true);
  73.   assert ((match_re "a.*c" "cbba")=false);
  74.   assert ((match_re "aa*" "x")=false);
  75.   assert ((match_re "aa*" "a")=true);
  76.   assert ((match_re "aa*" "aa")=true);
  77.   assert ((match_re "aa*" "ba")=true);
  78.   assert ((match_re "a*a*a" "a")=true);
  79.   assert ((match_re "a*a*a" "aaa")=true);
  80.   assert ((match_re "a*a*a" "xxxxx")=false)
  81.  
  82. let _ = match_re_test () (* no news is good news *)

OCaml translation of the regex match code in C.
I tried to beautify the code but it looks quite dirty due to the string operations. It will become more beautiful if we use a list of characters instead of native string as Scheme does in the suggested solution.

Insert increasing sequence of numbers in Emacs

8월 26th, 2009 No comments »

When coding in Emacs, I needed to insert an increasing sequence of integers as follows.

  1.  pdriver_object->MajorFunction[0] = NULL;
  2.  pdriver_object->MajorFunction[1] = NULL;
  3.  pdriver_object->MajorFunction[2] = NULL;
  4.  pdriver_object->MajorFunction[3] = NULL;
  5.  pdriver_object->MajorFunction[4] = NULL;
  6.  pdriver_object->MajorFunction[5] = NULL;

It’s easy to copy and paste the lines. Inserting a sequence of integers was the problem and I wrote a small Emacs Lisp code for that.

  1. (defun f (n)
  2.  (let ((ns (number-to-string n)))
  3.   (if (<= n 30)
  4.     (progn
  5.      (insert ns)
  6.      (next-line)
  7.      (backward-char (length ns))
  8.      (f (1+ n))))))
  9. (f 30)

This was my first practical elisp code. It required more time than typing in numbers, it’s very satisfactory. :)

Let’s Make A Deal! « Programming Praxis

8월 5th, 2009 No comments »

Let’s Make A Deal! « Programming Praxis.

Monty Hall 문제로 잘 알려져 있는 확률 문제를 실제로 시뮬레이션 해보는 프로그램.

아래는 OCaml 코드

  1. open Random;;
  2. open Array;;
  3. open Printf;;
  4.  
  5. let rec shuffle arr n =
  6.  if n = 0 then arr
  7.  else begin
  8.   let a = Random.int (length arr) in
  9.   let b = Random.int (length arr) in
  10.   let va = Array.get arr a in
  11.   Array.set arr a (Array.get arr b);
  12.   Array.set arr b va;
  13.   shuffle arr (n-1)
  14.  end
  15.  
  16. exception Found
  17. let find_unchosen_goat arr choice =
  18.  let ug = ref 0 in
  19.  try
  20.   Array.iteri
  21.    (fun i _ ->
  22.     if i != choice && Array.get arr i != 1 then begin ug := i; raise Found end
  23.     else ug := i)
  24.    arr;
  25.   0
  26.  with _ -> !ug
  27.  
  28. let find_change_choice arr old_choice unchosen_goat =
  29.  let cc = ref 0 in
  30.  try
  31.   Array.iteri
  32.    (fun i _ ->
  33.     if i != old_choice && i != unchosen_goat then begin cc := i; raise Found end
  34.     else cc := i)
  35.    arr;
  36.   0
  37.  with _ -> !cc
  38.  
  39. let check_choice arr choice = Array.get arr choice = 1
  40.  
  41. let deal change =
  42.  let doors = shuffle [|0;0;1;|] 10 in
  43.  let choice = Random.int 3 in
  44.  let unchosen_goat = find_unchosen_goat doors choice in
  45.  let last_choice =
  46.   if change then find_change_choice doors choice unchosen_goat
  47.   else choice
  48.  in
  49.  check_choice doors last_choice
  50.  
  51. (** Written by myself – simulate the whole game *)
  52. let simulate ngames =
  53.  let switch_game_result = Array.map (fun _ -> deal true) (Array.init ngames (fun i -> i)) in
  54.  let switch_wins = Array.fold_left (fun wins result -> if result then wins+1 else wins) 0 switch_game_result in
  55.  let stay_game_result = Array.map (fun _ -> deal false) (Array.init ngames (fun i -> i)) in
  56.  let stay_wins = Array.fold_left (fun wins result -> if result then wins+1 else wins) 0 stay_game_result in
  57.  Printf.printf "Winning rate for switch choice : %f\n" ((float_of_int switch_wins) /. (|>float_of_int ngames));
  58.  Printf.printf "Winning rate for stay choice : %f\n" ((float_of_int stay_wins) /. (|>float_of_int ngames))
  59.  
  60. (** Translation of suggested solution – simplified simulation*)
  61. let monty n =
  62.  Random.self_init ();
  63.  let rec monty n switch stay =
  64.   let auto,pick = Random.int 3, Random.int 3 in
  65.   if n = 0 then (switch,stay)
  66.   else
  67.    if auto = pick then monty (n-1) switch (stay+1)
  68.    else monty (n-1) (switch+1) stay
  69.  in
  70.  monty n 0 0
  71.  
  72. (** More simplified *)
  73. let monty2 n =
  74.  Random.self_init ();
  75.  let rec monty2 n switch =
  76.   let pick = Random.int 3 in
  77.   if n = 0 then switch
  78.   else
  79.    if pick = 0 then monty2 (n-1) switch
  80.    else monty2 (n-1) (switch+1)
  81.  in
  82.  monty2 n 0

결과를 보면 선택을 바꾼 경우 이길 확률이 2/3가 된다는 것을 볼 수 있다.

# monty2 1000;;
- : int = 674
# monty2 10000;;
- : int = 6657
# monty2 100000;;
- : int = 66647

좁은 문 – 앙드레 지드

7월 19th, 2009 No comments »

간만에 예비군 훈련 갔더니 아뿔사 그 지루한 시간에 대한 대비를 하지 못했다. 핸드폰에 시간 때우기용 만화나 판타지 소설을 담아가지 않은 것이다. 그런데 메모리 카드를 뒤져보니 아주 옛날에 넣어두고 잊어버린 소설이 한 편 있었다. 바로 앙드레 지드의 ‘좁은 문’이다. 유명한 소설이라 담아둔 것 같은데 전혀 들춰보지 않고 있다가 이러한 특수한 상황에 되니 그거라도 읽을 수밖에 없었다. 지루할 것 같다는 선입견을 가지고 보기 시작했는지 처음에 무척 길게 나오는 작가 소개 글이 너무 지겨웠다. 겨우 참아가며 읽어가니 한참 뒤에 실제 소설이 1인칭 시점으로 시작한다.

-여기서부터 미리니름 있음-

줄거리를 간단히 말하면 남자 주인공 제로옴이 사촌누나 알리싸를 사랑하는 내용인데, 서로 사랑하지만 결국 이루어지지 못하게 된다. 현재의 상식으로는 두 사람 사이의 친족관계 때문에 그럴 것 같지만, 소설에서는 친족관계 따위는 아무런 문제가 되지 않는다. 문제는 알리싸가 심하게 기독교에 심취하여 청교도스러운 (즉, 과도하게 도덕을 강조하고 쾌락을 배척하는) 생활을 하기 때문이다. 알리싸는 실제로 그 누구보다 제로옴을 사랑하지만, 기독교의 가르침을 너무 직접적으로 받아들이며 인생의 궁극적 목표를 하느님을 향한 사랑으로 정해버리게 된다. 그래서 두 양립 불가능한 사랑 사이에서 고뇌하다가 결국 몸도 상하고 젊은 나이에 세상을 뜬다.

작가가 이 소설에서 안티기독교를 주장하려는 걸 제쳐놓고 보면, 두 사람 사이의 안타까운 사랑 얘기를 하고 싶었던 것일 텐데, 약간 억지스러운 설정에 눈을 감으면 사랑의 묘사는 나름 훌륭한 것 같다. 알리싸가 제로옴과 하느님 사이에서 갈팡질팡하며 결과적으로 (심하게 말하면) 제로옴을 갖고 논 게 됐는데 그게 참 어이없으면서도 애절한 마음을 잘 표현한 것 같다. 나중에 곱씹어보면 알리싸는 애초에 그냥 수녀가 되던가 해서 제로옴을 단념했어야 하는데 아무것도 안줄거면서 끝까지 놓아주지 않는 게 좀 억지스럽긴 했다. 사실 앞에서 제쳐두었던 안티기독교도 소설의 큰 내용을 이루고 있긴 하다. 주인공들의 대화가 상당히 직접적으로 이 문제를 다루고 있기 때문이다. 결론은 ‘신도 적당히 믿어라’ 인 듯 하다.

극도로 지루한 환경에 의해 거의 반 강제적으로 읽게 된 소설이지만 그래도 한 번 잡고 읽으니 별로 길지도 않아서 끝까지 다 읽을만한 흥미있는 책이었다. 하지만 좀 더 치열한 사랑 이야기를 읽고 싶으면 차라리 에밀리 브론테의 ‘폭풍의 언덕’을 추천하고 싶다.

눈 먼 시계공 – 리처드 도킨스

6월 28th, 2009 2 comments »

리처드 도킨스의 ‘눈 먼 시계공’(책에는 ‘눈먼 시계공’이라고 되어있는데 ‘눈’과 ‘먼’을 띄는 게 맞는 것 같다)을 드디어 다 읽었다. 2주 쯤 전까지 한참 재밌게 읽다가 두어 장을 남겨두고 잠시 한 눈을 팔았더니 금방 시간이 지나가 버렸다. 그래서 다시 맘 잡고 읽었더니 금방 읽을 수 있었다. 책의 중후반까지 책의 가장 중요한 내용인 진화론의 자연 선택에 의한 적응적 복잡성을 설명하고 있고, 마지막에 부분은 다른 경쟁 이론(이라고 쓰고 ‘경쟁상대도 안되는 이론’이라고 읽음)들의 문제점을 지적하며 진화론이 가장 합리적이며, 실제로는 적응적 복잡성을 설명하는 유일한 이론이라는 것을 주장하고 있다.

진화론 자체에 대한 설명은 (비록 내가 전문가는 아니지만) 흠잡을 곳 없이 훌륭하다고 생각한다. 다양하고 설득력 있는 예를 들어가며, 또한 일반인을 위한 책답지 않게 상당히 정교한 논리로 무장했지만 무척 읽기 쉽게 설명하고 있다. 번역도 상당히 좋고 역주도 너무 많지도 적지도 않게 들어가 있는 것 같다.  내용 중에 특히 인상적이었던 것은 인간과 문어의 눈을 비교한 것과 박쥐의 ‘반향 위치 결정’에 대한 소개였다. 또, 점토의 진화의 예를 들어 최초의 생명체에 대한 설명을 소개한 것도 아주 흥미로웠다.

뒷부분의 분류학에 대한 이야기나 기타 이론에 대한 공격은 사실 좀 따분하다. 이 책이 1986년도에 처음 나온 것을 감안하면, 그 당시에는 여전히 첨예한 논쟁이 있었던 것 같지만, 아마 지금은 라마르크주의자나 돌연변이주의자인 생물학자는 존재하지 않을 것 같다. 물론 그 중에서도 가장 설득력 없는 이론을 믿는 창조론자는 여전히 존재하는 게 상당히 안타깝긴 하다.

책을 읽으면서 나도 진화론에 대해 정확하게 알지 못하고 있었다는 사실을 알게 되었다. 사실 진화론에 대해서 공부한 건 고등학교 생물 시간이 마지막이었고, 거기서도 별로 많은 것을 다룬 것 같진 않다. 고등학교나 그 이전에 이 책을 읽었더라면 좋았을 것 같다는 생각이 든다. 비록 번역은 2004년에 처음 나왔지만… 그 유명한 ‘이기적인 유전자’도 아직 읽어보지 못했는데 읽어봐야 할 것 같다. 어쨌든 누구에게라도 추천하고 싶은 아주 훌륭한 책이다. 리처드 도킨스는 훌륭한 학자에 훌륭한 저술가이기도 한데 거기에 매우 멋진 점은 공격적으로 글을 쓴다는 것이다. 물론 공격적으로 글을 쓰는 것은 누구나 할 수 있지만(조중동 찌라시 논설위원들같은 놈들 처럼), 논쟁을 피하지 않으며 도킨스처럼 자신의 주장에 대한 아주 세세한 부분까지 모두 정확하게 이해하고 논리적인 주장으로 그러한 글을 쓰는 것은 결코 쉽지 않은 일이다. 이제 ‘The God Delusion’을 읽어야겠다. :)

책 사다

6월 12th, 2009 1 comment »

저번 주 토요일, 6월6일을 맞아 그동안 목록에 담아 두었던 책들을 질렀다.

  • 기억을 찾아서
  • The World Is Flat [Further Updated and Expanded]
  • 갈릴레오의 아이들
  • The God Delusion
  • House of Many Ways
  • The Origin of Species
  • 세상에서 가장 쉬운 한자 공부법
  • 브레인 룰스

HoMW는 내가 ‘Castle in the Air‘에서도 썼듯이 재밌게 보던 판타지 소설 시리즈의 최근 책이다. 어린이날은 한참 지났지만 그래도 지금이라도 갖게 되어 기쁘다. 전작들이 하나같이 모두 훌륭해서 이번 것도 충분히 나를 만족시켜 주리라 기대한다.

TOoS는 매우 중요하고 훌륭한 과학 고전으로써, 최근 재밌게 읽고 있는 ‘눈먼 시계공’에 자주 언급되고 있어서 원전을 읽어봐야겠다는 생각을 들게 했다.

TGD는 ‘눈 먼 시계공‘의 저자인 리처드 도킨스의 또다른 – 사실 이 사람의 책은 거의 다 유명하지만 – 유명한 책으로써, 특히 종교를 다루어서 더욱 논란이 된 책이다. 2년 전 처음 나왔을 때부터 계속 읽고 싶었지만 꾹 참고 있다가 이번에 함께 질렀다.

‘기찾’과 ‘브룰’은 한겨레 서평을 보고 재밌어 보여서 샀다. 이건 역시 몇 달 전에 읽었던 ‘아내를 모자로 착각한 남자’와 맥락을 같이 하는 뇌에 관한 책들이다.

TWIF는 현성이가 최근 읽고 있는 책인데, 재밌다고 추천해서 함께 샀고 ‘갈아’는 인터넷책방을 둘러보다가 르귄의 이름이 붙어있길래 냉큼 샀다.

원서를 좀 많이 샀는데. 원서를 선택한 가장 큰 이유는 원서가 더 저렴했기 때문이고(TWIF,TGD,TOoS), 두 번째 이유는 원서로 밖에 나와있지 않은 책이 있으며(HoMW), 마지막 이유는 영어로 읽는 훈련을 하기 위해서이다.

아, ‘세가쉬한공’은 싼 맛에 넣었는데, 이상하게 내가 이용하는 인터넷 책방에서 5만원 이상을 주문하면 2000원을 적립해주지만 10만원을 산다고 해서 4000원을 적립해주지는 않길래 적당히 5만원씩 두 번 주문하기 위해서 끼워 넣은 책이다. 이름이 매우 선정적인데 몇 천원 정도 값만 해주면 좋겠다.

노무현 전 대통령 서거에 관한 생각

5월 24th, 2009 No comments »

이 소식을 처음 들었을 때는 참으로 어처구니 없다는 생각밖에 안들었지만 좀 더 천천히 생각해보니 그럴만 하니까 그랬구나 하는 생각이 들었다. 그는 한 평생을 단 한 번도 자신의 뜻을 굽히지 않고 살아온 사람이었다. 꺾일지언정 굽히지는 않는다는 말이 딱 들어맞는 사람이었고, 엄청난 수모와 배신에 끝까지 버티다가 이렇게 꺾여져 간 것 같다. 결국 정말 너무나 노무현다운 선택이 아니었나 싶다. 하지만 여전히 좀 더 곁에 있었으면 하는 바람을 지울 수 없다. 어쨌든 간에 노무현은 한국 역사에서 가장 훌륭한 지도자였던 사람이었으며 영원히 사람들에게 기억될 것이다.

피타고라스의 창 » 타자 타율이 0.334면, 타자는 최소 287타수가 필요하다는 사실의 증명

5월 15th, 2009 1 comment »

피타고라스의 창 » 타자 타율이 0.334면, 타자는 최소 287타수가 필요하다는 사실의 증명.

재밌는 문제가 보여서 풀어보았다.

타자 타율이 0.334면, 타자는 최소 몇 타석이 필요한가? (TAOCP에 나온 문제라고 함)

a타수 b안타의 타율이 b/a이므로, 반올림 해서 0.334의 타율이 되려면, a와 b가 0.334 <= b/a < 0.3345를 만족해야 한다. 이를 만족하는 최소 자연수 a를 찾으면 된다.

아래는 Ocaml 코드.

  1. let c1 = 1000.0 /. 334.0 in
  2. let c2 = 10000.0 /. 3345.0 in
  3. let rec range i j = if i > j then [] else i :: (range (i+1) j) in
  4. let min_int_between i1 i2 =
  5. let minv,maxv = min i1 i2, max i1 i2 in
  6. match compare minv maxv with
  7. -1 -> if maxv - minv > 1 then Some (minv+1) else None
  8. |    _ -> None
  9. in
  10. let hit a b = (float b) /. (|>float a) in
  11. let blist = range 0 200 in
  12. let aoptlist = List.map (fun b ->
  13. let f1,f2 = c1 *. (|>float b), c2 *. (|>float b) in
  14. let i1,i2 = (truncate (ceil f1)), (truncate f2) in
  15. (b,min_int_between i1 i2)) blist
  16. in
  17. List.iter (fun (b,aopt) ->
  18. match aopt with
  19. None -> ()
  20. | Some a -> Printf.printf "%d/%d %f\n" b a (hit a b)) aoptlist;;

아래는 결과.

96/287 0.334495
97/290 0.334483
98/293 0.334471
99/296 0.334459
100/299 0.334448

즉, 적어도 287타수는 해야 0.334의 타율을 얻을 수 있다. 저 블로그의 내용을 보면 연분수 전개라는 방법이 있다는데 뭔지는 모르겠다. 아예 이름이 생소한데, 학교에서 배운 적은 없는 것 같다..