SICP란 "Structure and Interpretation of Computer Programs"의 약자로 MIT에서 프로그래밍/전산 기초 교제로 사용하고 있는 책이다. Herold Abelson, Gerald Jay Sussman, Julie Sussman이 쓴 책이다.
10년전 --;; 대학원 다닐때 CS230 System Programming조교로 있을 때 당시 나의 지도교수셨던 이광근박사님께서 해당 과목을 담당하셔서 조교로 들어가면서 교제로 쓰인 이 책과 scheme을 처음 접했다.
대학원생이었던 내가 볼때도 상당히 인상깊은 교제였다. 컴퓨터에 대해 서술하거나 언어의 문법에 대해 이야기 하기 보다는 문제를 먼저 제시하고 해당 문제를 프로그램 로직으로 어떻게 해결하는지를 서술하는 형태로 구성이 되어 있고, 문제의 경우도 해당 분야에 대한 기초적인 이해가 있어야 쉽게 이해할 수 있는 것들이 많았었다.
루비를 처음 접하면서 이 책의 여러 예제나 주제들을 루비를 사용해 풀어보면 어떨까 하는 생각이 들었고, 그를 기초로 초안을 작성했었는데, 역시나 시작은 창대하였으나 끝은 삐적 골아서, 초반에 한 두주 열심히 3장까지는 골격을 잡았으나, 나중엔 손을 떼고 말았다.
많은 일본드라마가 그렇든 만화가 원작이고, 만화 캐릭터가 살아있는 것 처럼 꼭 맞는 캐스팅에 만화적인 연출, 거기에 음악 만화에서는 상상해야만 하는 음악이 귀로 생생하게 들리는 드라마이다.
그 그중에 드라마에 나왔던 오케스트라곡...
01. 베토벤 : 교향곡 제7번 제1악장 (노다메 오케스트라 버전) 02. 베토벤 : 교향곡 제7번 제4악장 (노다메 오케스트라 버전) 03. 베토벤 : 교향곡 제9번 제1악장 (팀파니 GET OUT VERSION) 04. 거쉬인 : 랩소디 인 블루 (피아니카 버전) 05. 라흐마니노프 : 피아노 협주곡 제2번 / 제1악장 06. 모짜르트 : 오보에 협주곡 / 제1악장 07. 브람스 : 교향곡 제1번 / 제1악장 08. 브람스 : 교향곡 제1번 / 제4악장 09. 사라사테 : 카르멘 환상곡 10. 베토벤 : 교향곡 제7번 / 제4악장 (도쿄도 교향악단 데프리스트) 11. 거쉬인 : 랩소디 인 블루 (엔딩 버전) 12. 베토벤 : 피아노 소나타 제8번 「비창」 / 제2악장 (노다메 버전) 13. 모짜르트 : 2대의 피아노를 위한 소나타 2장조 제1악장 / 2소절로 틀리지마! 14. 모짜르트 : 2대의 피아노를 위한 소나타 2장도 제1악장 / 제1악장 15. 모짜르트 : 오페라 「마적」 에서 / 밤의 여왕의 아리아 16. 베토벤 : 바이올린 소나타 제5번 작품24 「봄」 / 제1악장 (미네,노다메 버전 ~빛나는 봄의 기쁨과 아내~) 17. 베토벤 : 바이올린 소나타 제5번 작품24 「봄」 제1악장 18. 베토벤 : 교향곡 제7번 피아노 버전 / 제1악장에서 (노다메 버전) 19. 바흐 : 무반주 바이올린을 위한 파르티타 2단조 제2번 / 사라반드 20. 라흐마니노프 : 피아노 협주곡 제2번 2대 피아노 / 제1악장에서 (노다메,치아키 2대 피아노 버전) 21. 쇼팽 : 에튜드 작품10-4 / 노다메 혼의 에튜드 22. 드뷔시 - 기쁨의 섬 23. 스트라빈스키 - 페트르슈카부터의 제3악장 / 제1악장 : 러시아의 춤 에서 24. 슈베르트 - 피아노 소나타 제16번 이단조 D.845 / 제1악장 25. 모짜르트 - 2대의 피아노를 위한 소나타 이장조 제1악장 / 노다메,치아키 버전
드라마를 보다 보니 이번에 연말정산 받으면 콤포넌트라도 사서 라흐마니노프 협주곡을 들어보고 싶은 생각이 샘솓는다.
혜원이가 그네를 너무 좋아해서(문에 가로대를 박아넣고 줄로 매단 그네도 좋아하지만,
혜원이 겨드랑이 아래로 내가 손을 넣고, 가슴 앞으로 깍지를 껴서, 직접 팔로
들어올려서 왔다갔다 하는 그네를 좋아한다. 아무데서나 즐길 수 있고..)
항상 집에오면 '아빠 그네'하고 졸라댄다. 하지만, 혜원이는 이미 유아를 벗어나
몸무게로는 소녀의 대열에 합류한 녀석이라, 체력이 딸리는 아빠에겐 늘 힘든 일이다.
(15Kg이 넘어서 이젠 가벼운 마음으로 놀아줄 수 있는 상대가 아니다...)
오늘은 비도 오고..(아이구 허리야~~) 꽤가 나서, '아빠.그네~~'하는 녀석에게
'오늘은 새로운 놀이를 해보자~~. 혜원아 어떤 놀이가 좋겠니?' 하고 살살 꼬득여서
드디어 '동물원놀이'를 시작했다.
컨셉은 각자 동물이 되어 그냥 노는거. 처음에 물고기놀이.
"로 시작하는 스트링, 정규식, 그리고 command output 식의 경우 #{expression}형태는 해당 expression을 계산한 값으로 확장됩니다. 만약 식이 $나 @로 시작하는 변수라면 식을 {}로 쌀 필요가 없습니다. #은 #{나 #$, #@로 사용되지 않을 경우에는 #자체로 평가됩니다.
예: a = 1 b = "a = # #{a}" # b = "a = # 1"
- line-oriented string literals(Here document)
긴 문자열을 입력시에는 "Here document"라 불리는 유서깊은 방법을 사용할 수 있습니다. << 다음에 문자 입력을 중단할 때 종결자로 사용할 문자열/Identifier을 넣게 됩니다. 이때 <<과 종결자 사이에는 빈칸이 없어야 합니다.
이때 "를 사용하면 큰따옴표로 묶인 문자열의 규칙에 따라 해당 부분이 계산된 후 진행이 되고, '로 싸게 되면 command output에 따라 실행이 되고 진행이 됩니다.
종결자는 줄의 맨 앞에 있을 경우에만 체크가 되지만, -가 종결자 앞에 붙으면 입력되는 문자열에서 줄 처음의 연속된 공백문자는 무시되게 됩니다. 다음 예를 보세요.
print <<EOF The price is #{$Price}. EOF
print <<"EOF"; # 위와 같음 The price is #{$Price}. EOF
print <<`EOC` # 커맨드 실행
echo lo there EOC
# <<를 연속으로 쓸수도 있습니다. # 이때 종결자는 <<에서 사용된 순서대로 나타나야 합니다. # 아래 예에서 맨 처음 bar는 foo이전에 나와서 그냥 스트링으로 처리됩니다. print <<"foo", <<"bar" I said foo. bar foo I said bar. bar
myfunc(<<"THIS", 23, <<'THAT') # 함수 인자로 사용가능합니다. Here's a line or two. THIS and here's another. THAT
if need_define_foo eval <<-EOS # 입력되는 스트링 앞에 스페이스나 탭이 들어가면 무시합니다. def foo print "foo\n" end EOS end
-Numeric literals
정수 : 123 123_4(=1234, 숫자 사이의 _는 무시) 부동소수점수 : 123.45 1.2e-3 16진 정수 : 0xffff 2진 정수 : 0b010101 8진 정수 : 0377 ?a : 'a'의 아스키코드(=97) ?\C-a : control-a의 아스키코드(=1) ?\M-a : meta-a의 아스키코드(=225) ?\M-\C-a : meta-control-a의 아스키코드(129) :symbol : symbol(=identifiers, 변수명, 오퍼레이터)에 해당하는 정수
- Variables and constants
전역 변수, 인스턴스 변수, 지역 변수, 클래스변수, 그리고 클래스 상수가 있으며, 변수이름 길이에는 제한이 없습니다.
= Global variables $foobar, $/와 같이 $로 시작하면 전역변수입니다. 초기화 되지 않은 전역변수는 nil 값을 가집니다. 따라서, 초기화 하지 않은 전역변수를 사용해도 오류/예외상황이 발생하지 않습니다.
= Instance variables @foobar와 같이 @로 시작하면 self 객체의 인스턴스 변수입니다. 초기화 되지 않은 변수는 nil값을 가집니다.
class Example def test @value = 1 end def test2 @value end end
a = Example.new # Example의 인스턴스 생성 b = Example.new # Example의 인스턴스 생성 a.test2 # nil b.test # test를 실행 b.test2 # 1 a.test # test를 실행 a.test2 # 1
= Constants 식별자(identifier)가 FOOBAR와 같이 대문자로 시작하는 경우에 상수가 됩니다. 상수 정의는 클래스 정의하는 곳에서 대입으로 이뤄지게 됩니다. 상수값을 바꾸거나, 초기화되지 않은 상수를 억세스하는 것은 NameError 예외를 발생시킵니다.
상수는 다음 부분에서 억세스 될 수 있습니다.
* 상수가 정의된 클래스/모듈의 몸체에서 (해당 클래스/모듈의 메소드나 그 클래스/모듈에 내포된 모듈/클래스 정의 부분을 포함) * 상수가 정의된 클래스를 상속하는 클래스에서 * 상수를 정의한 모듈을 포함하는 클래스나 모듈에서
클래스 정의는 상수를 자동으로 정의하게 되며, 클래스 이름은 상수로 취급됩니다.
클래스/모듈에 정의된 상수를 사용시에는 클래스명::상수명을 사용합니다. ::상수명처럼 사용하면 Object클래스에 정의된 상수를 사용하는 것입니다.
= Local variables
foobar, _foo와 같이 소문자나 _로 시작하는 변수는 지역변수이거나 메소드 호출입니다. 클래스/모듈/메소드 정의의 몸체에서 지역변수에 첫번째로 값을 대입하는 것이 지역변수의 선언이 됩니다. 선언이 되지 않은 지역변수 사용은 인수(argument)가 없는 메소드 호출로 간주됩니다. 따라서 해당 이름이 메소드로도 사용되지 않고, 값이 대입된 경우도 없는 이름이라면 NameError 예외가 발생하게 됩니다.
지역변수는 해당 블럭 안에서만 사용 가능합니다. 또한, 지역변수는 '동적 변수' 입니다. 예를 들어: i0 = 1 loop { i1 = 2 print defined?(i0), "\n" # true print defined?(i1), "\n" # true break }
위에 보듯, i0는 안쪽 loop블럭 안에서도 유효하고, 그 밖에서도 유효하지만, i1은 loop블럭 안에서만 유효하고, 그 밖에서는 유효하지 않습니다.
= Pseudo variables 다음 변수들은 pseudo variable이라 불리는 특별한 변수입니다. self 현재 메소드를 처리할 객체(the receiver of the current method) nilNilClass의 유일한 인스턴스 (the sole instance of the Class NilClass(represents false)) trueTrueClass의 유일한 인스턴스 (the sole instance of the Class TrueClass(typical true value)) falseFalseClass의 유일한 인스턴스 (the sole instance of the Class FalseClass(represents false)) __FILE__ 현재 소스파일의 이름(the current source file name) __LINE__ 현재 소스파일안에서 현재 라인 번호(the current line number in the source file)
기본적으로 ASCII코드로 작성되며, case sensitive한 언어입니다. whitespace로 스페이스, 탭, 버티컬탭, 캐리지리턴, 백스페이스, 폼피드를 사용합니다.뉴라인은 식이 다음 줄에서도 계속 이어진다는것이 명확한 경우에만 whitespace로 취급되며, 그렇지 않은 경우에는 스테이트먼트를 종료시키는 종결자로 사용되게 됩니다.
어떤 줄이 =begin으로 시작하면, =end로 시작하는 줄이 나올때까지 전체가 무시됩니다.(코멘트와 같은 역할)
- Reserved Words
BEGIN, class ,ensure, nil, self, when, END, def, false, not, super, while, alias, defined, for, or, then, yield, and, do, if, redo, true, begin, else, in, resue, undef, break, elsif, module, retry, unless, case, end, next, return, until
문법(Syntax)
- Program
루비 프로그램인 식의 시퀀스입니다. 각 식은 ;나 뉴라인으로 구분되며, 줄끝의 \로 식을 끝내지 않고 다음줄로 이어서 사용할 수 있습니다.
- Expression
식은 ()로 그룹을 만들 수 있습니다.
- String Literals
문자열은 "나 '로 둘러싼 리터럴입니다. "을 사용한 경우 \을 사용한 escape를 지원하고, expression substitution을 지원합니다. '를 사용한 경우에는 \'와 \\를 만 지원하고, escape시퀀스나 expression substitution을 지원하지 않습니다.
%로 시작하는 문자열은 \가 문자열에 너무 많이 들어가는 것을 막기 위해 사용합니다.
%q/STRING/은 'STRING'을, %Q/STRING/이나 %/STRING/은 "STRING"을 대신합니다. /의 위치에 /가 아닌 임의의 non-alphanumeric delimiter를 사용 가능합니다. perl의 q/나 qq/를 생각하면 됩니다. 심지어는 /대신 뉴라인을 사용해도 됩니다. 또한 %[와 같이 %다음에 오는 문자가 쌍이 있는 여는괄호등 이라면 닫는 분자는 그에 상응하는 닫는 괄호가 와야 합니다. (%[this is another string notation], %|this is also another string|)
- backslash notation
\t : tab(0x09) \n : newline(0x0a) \r : carriage return(0x0d) \f : form feed(0x0c) \b : backspace(0x08) \a : bell(0x07) \e : escape(0x1b) \s : space(0x20) \nnn : octal ascii code nnn \xnn : hex. ascii code nn \cx : control - x \C-x : control - x \M-x : meta -x (x | 0x80) \M-\C-x : meta-control-x \x : 문자 x 자체
- Command output
%x/COMMAND/나 `COMMAND`를 사용하면 subshell command를 실행하여 그 결과(=standard out으로 출력된 값)를 저장할 수 있습니다. 이때, 먼저 escape sequence interpretation과 expression substitution이 일어나고, 그 후에 subshell command 실행이 일어나게 됩니다. 커맨드는 문자열이 evaluation되는 매 경우에 다시 불립니다.
- Regular expression
/로 구분된 스트링은 정규식입니다. 마지막 /뒤에 오는 문자들은 정규식의 옵션입니다. 예를 들어 /Ruby/i와 같은 경우 Ruby가 정규식, i는 옵션이 됩니다. %r/STRING/도 /STRING/과 동일합니다.
옵션의 예: i : 치환을 첫번째 계산시에만 진행 x : 확장된 정규식 p : POSIX모드
정규식 :
^
라인/스트링 시작(beginning of a line or string)
$
라인/스트링 종류(end of a line or string)
.
뉴라인 제외한 모든 문자 한글자(any character except newline)
\w
단어를 이루는 문자(word character[0-9A-Za-z_])
\W
단어를 이루지 못하는 문자(non-word character) - \w의 여집합
\s
공백문자(whitespace character[ \t\n\r\f])
\S
비공백문자(non-whitespace character) - \s의 여집합
\d
숫자(digit, same as[0-9])
\D
비숫자(non-digit) - \d의 여집합
\A
스트링의 시작(beginning of a string)
\Z
스트링의 끝/스트링의 끝 이전의 뉴라인(end of a string, or before newline at the end)
\z
스트링의 끝(end of a string)
\b
단어 경계(word boundary(outside[]only))
\B
비단어의 경계(non-word boundary)
\b
백스페이스(backspace(0x08)(inside[]only))
[ ]
[]안에 있는 문자들 중 어느 하나(any single character of set)
*
바로 직전 정규식의 0번이상 반복(0 or more previous regular expression)
*?
바로 직전 정규식의 0번 이상 반복-그리디하지 않은(0 or more previous regular expression(non greedy))
+
바로 직전 정규식의 1번 이상 반복(1 or more previous regular expression)
+?
바로 직전 정규식의 1번 이상 반복-그리디하지 않은(1 or more previous regular expression(non greedy))
{m,n}
바로 직전 정규식의 최소 m에서 최대 n번 사이의 반복(at least m but most n previous regular expression)
{m,n}?
바로 직전 정규식의 최소 m에서 최대 n번 사이의 반복 - 그리디하지 않은(at least m but most n previous regular expression(non greedy))
?
바로 직전 정규식이 하나 또는 0번 (0 or 1 previous regular expression)
|
선택(alternation)
( )
정규식을 묶음(grouping regular expressions)
(?# )
코멘트(comment)
(?: )
backreference없이 묶음(grouping without backreferences)
(?= )
너비 0인 양의 룩어헤드 어서션(zero-width positive look-ahead assertion)
(?! )
너비 0인 음의 룩어헤드 어서션(zero-width negative look-ahead assertion)
(?ix-ix)
정규식 안에서 i와 x 옵션 적용을 끄거나 켬. 이 변경은 이 정규식이 포함된 그룹안으로 제한됨(turns on (or off) `i' and `x' options within regular expression. These modifiers are localized inside an enclosing group (if any))
(?ix-ix: )
non-capturing 그룹안에서 정규식 안에서 i와 x옵션 적용을 끄거나 켬(turns on (or off) `i' and `x' options within this non-capturing group
(non-capturing그룹이 뭔지는 잘 모르겠습니다. 정규식에 대해 컴파일러 시간에 배운정도 밖에 잘 몰라서... 공부좀 더 하고 내용을 다시 알려드리죠...)
와이프가 진통이 규칙적으로 오기 시작한건 9월 7일 오전 5시경이었습니다. 첫 아기라 뭐가 뭔지 몰라서, 일단 장모님댁으로 가서 교회도 못가고 그날 저녁까지 초조하게 진통 간격이 짧아지고, 더 많이 아파지길 기다렸죠. 아침부터 계속 5분 간격 진통이었는데, 저녁이 되어도 계속 5분 간격이더군요. 중간에 자꾸 걷고, 돌아다니면 아이가 좀 빨리 나올까 해서, 아내와 처형과 같이 집에서 1~2Km정도 떨어진 곳까지 산책삼아 나갔다 오기도 하고, 집에서 임산부 기체조 시간에 배웠던 체조도 하고 하면서 기다렸습니다.
그러나, 간격이 안줄고, 진행 정도를 잘 몰라서 불안한 맘도 있고 해서 더이상 참지 못하고 7일 저녁 6시경 병원에 갔습니다. 병원에 갔는데, 분만실로 바로 올라가라고 하더군요. 분만실에 가니까, 남편은 나가있고, 산모만 남아있으라는 것입니다. 가뜩이나 불안한데, 혼자 남아있을 아내를 생각하니 마음이 아팠습니다. 밖에서 10여분 기다렸을까요? 다시 보호자를 부르기에 들어갔습니다. 가족 분만실에 들어가라고 하더군요. 간호사 말로는 자궁구가 2Cm정도 열렸고, 초산이라 10시간에서 14시간은 더 걸릴 수 있다고 하면서, 진행을 기다리라고 하더군요. 별수 있습니까? 꼬박 밤을 새면서 기다렸습니다. (자궁구가 10Cm열리면 아기가 나온다고 생각하심 됩니다.)
밤새 진통 간격은 줄지 않고, 아픈 정도만 점점 커졌습니다. 들어가자 마자 와이프 손목에 링거액을 꽂는 바람에 진통을 하는 내내 운동도 못하고, 그냥 하릴없이 침대에만 누워서 버텨야만 했습니다. 아직 자궁구가 적게 열려서인지 간호사들은 밤새 들여다 보지도 않더군요. 차라리 집에서 더 버틸껄 왜 왔나 싶었습니다.
다음 날 아침이 되어서 다시 내진을 받았는데, 겨우 3Cm열렸답니다. 와이프가 너무 힘들어 하면서, 좀 더 아파도 진통을 빨리 해서 빨리 낳자고 해서, 자궁수축 촉진제를 링거에 꽂아서 맞았습니다. 그런데, 그렇게 하니 자궁 수축이 심해져서인지 너무너무 아파 하더군요. 결국 다시 간호사에게 말해 옥시토신은 제거하구, 진통제를 한방 맞았습니다.
진통 간격이 5분에서 3분으로 줄어든게 10시경. 그때부터 와이프와 저의 고생은 시작되었죠. 허리가 너무너무 아파서 진통이 올때마다 허리를 세게 두들겨야 했습니다. 너무 아파서 계속 제왕절개 했으면 좋겠다는 소리를 하면서도 그냥 참고 견뎌냈죠. 12시가 되었는데, 자궁구는 5Cm밖에 안 열렸습니다. 진통은 심해지고, 점점 더 허리가 아파서 힘들어 하는 와이프 보면서 너무 안쓰럽더군요. 그냥 그렇게 아파하면서 오후 4시정도가 되니, 자궁구가 8Cm정도 열리고, 간호사가 2~3시간 정도 안에 아이가 나올거라구 이야기 해주더군요.
이때부터가 클라이막스였습니다. 그동안 아팠던거보다 훨씬 더 아파서 (음. 와이프 말로는 생리통 1000만배라고 하던데...) 허리를 두들겨 주면서도 허리가 부서지지나 않을까 걱정을 했답니다. 약하게 두들기면 더 세게 해달라고 계속 소리를 질러서요. 아기 머리가 골반 사이에 자리를 잡을때, 반바퀴 정도 회전을 하게 되는데, 이때 허리가 가장 아프다고 합니다.
5시정도부터는 진통하면서 힘을 주기 시작했습다. 30분 정도 지나니 간호사가 분만 준비를 하더군요. 조금 지나 의사와 간호사들이 들어오고, 가족들은 밖에서 기다리라고 했습니다. 한 20분쯤 기다렸을까, 아기 아빠만 들어오라고 해서, 가보니, 마지막 한번만 힘을 주면 될꺼라며, 와이프를 안고 도와주라고 하더군요. 막판에 한 1분간 이를 악물고(정말 이를 악물면 이가 나간다고 이를 마주치지 않고도 이를 악물고(?) 힘을 줬습니다.) 힘을 주니 아이 머리가 밖에 나온게 보였습니다. 의사가 아이를 빼내고, 탯줄을 제가 가위로 자르고, 아이를 준비한 아기 바구니에 넣고, 조금 지나니 숨을 쉬면서 울음을 터뜨리더군요. 팔, 다리, 손가락, 발가락 갯수, 코, 입, 눈, 귀 확인해 보고, 건강한 아이라면서 아기는 데리고 가고, 와이프는 태반 등등 출산 후 나와야 할것들이 나올때까지 더 분만실에 있었습니다. 아기 무게를 재보니 3.64Kg이었습니다.
아이가 태어나는 순간, 절로 눈물이 나더군요. 왠지 실감이 나지 않으면서도, 안심이 되고, 감사한 마음에 감사하단 말이 계속 입 밖으로 나왔습니다. 아기를 뱃속에서 키우느라 10개월간 고생하고, 거기에 출산의 고통까지 너무너무 힘든 과정을 통해 한 생명이 탄생하는것을 옆에서 보면서, 집사람에게 너무 미안하고, 고마왔습니다.
이제는 아이와 엄마 모두 산후조리원에서 쉬고 있습니다. 아기는 밥을 너무 많이 먹어서 먹보로 소문났습니다. 엄마 젖도 잘 먹고, 엄마 젖으론 양이 안차서 분유를 또 먹습니다. 잘때는 배네짓이라고 하죠? 웃기도 하고 찡그리기도 하고, 기침도 하고, 정말 수많은 표정과 몸짓을 하는데, 너무너무 이쁘고 사랑스럽습니다. ^^
이제 1주일이 넘는 시간이 지났고, 아이는 젖도 많이 먹고, 이젠 4Kg정도 나갑니다. 많이 먹고, 많이 싸고, 많이 자고.. 그냥 잠자는 아이만 보구 있어도 너무너무 행복하고 시간이 잘 갑니다. 잘 자라주고 있는 우리 혜원이와 울 집사람에게 그저 감사할 따름입니다. ^^