2. 시작

얼랭 설치하기

Ubuntu의 경우..

sudo apt-get install erlang

 

셸 시작하기

터미널 창에서 erl 이라고 입력하고 얼랭을 시작하자.

$ erl

jonathan@jonathan-laptop:~$ erl
Erlang R13B03 (erts-5.7.4) [source] [smp:4:4] [rq:4] [async-threads:0] [hipe] [kernel-poll:false]

Eshell V5.7.4  (abort with ^G)
1> 20 + 30.
50
2>

 

간단한 정수 연산

jonathan@jonathan-laptop:~$ erl
Erlang R13B03 (erts-5.7.4) [source] [smp:4:4] [rq:4] [async-threads:0] [hipe] [kernel-poll:false]

Eshell V5.7.4  (abort with ^G)
1> 2 + 3 * 4.
14
2> (2 + 3) * 4.
20
3> 123456789 * 987654321 * 112233445566778899 * 998877665544332211.
13669560260321809985966198898925761696613427909935341
4> 16#cafe * 32#sugar.
1577682511434
5>

 

변수

어떤 명령의 결과를 저장하여 나중에 사용하려면 어떻게 할까? 그게 바로 변수의 역할이다.

1> X = 123456789.
123456789

– 모든 변수는 대문자로 시작해야 한다.

어떤 변수의 값을 보려면, 그냥 그 변수명을 입력하면 된다.

2> X.
123456789

만약, 변수 X 에 다른 값을 할당하려 한다면 오류 메시지를 발견할 것이다.

1> X = 1234567.
1234567
2> X = 890.
** exception error: no match of right hand side value 890

이는 다음의 이유에서 발생하는 오류이다.
– 첫째, X는 변수가 아니다. 적어도 자바나 C 같은 언어에서 쓰는 의미의 변수로 생각해서는 안된다.
– 둘째, = 은 할당 연산자가 아니다.

 

뭔가 잘못되어 시스템이 응답이 없다면, 그냥 Ctrl+C 를 누르자.

BREAK: (a)bort (c)ontinue (p)roc info (i)nfo (l)oaded
(v)ersion (k)ill (D)b-tables (d)istribution

와 같이 나타날 것이다.
A를 누르면 얼랭 세션을 중단할 수 있다.

 

뜻하지 않는 변수

얼랭은 ‘단일 할당 변수(single assignment variable)’를 가진다. 그 이름이 의미하는 듯, 단일 할당 변수는 값을 오직 한 번만 받을 수 있다. 일단 한번 설정된 변수의 값을 변경하려고 하면 오류가 발생한다.

값이 할당된 변수를 ‘바운드(bound)’ 변수라 부르며, 그렇지 않은 변수는 ‘언바운드(unbound)’ 변수라 부른다. 모든 변수는 언바운드에서 시작한다. 그러나 일단 값을 담으면, 영원히 그 값을 보유한다.

변수의 범위(scope)란 그 변수가 정의된 어휘 단위(lexical unit)를 말한다. 따라서 만약 X가 어떤 단일 함수 절 내에서 사용되면, 그 변수의 값은 절 밖으로 나가지 못한다. 동일한 함수에서 여러 다른 절들이 공유하는 그런 전역(global) 또는 프라이빗(private) 변수 같은 것은 없다.

 

패턴 매칭

대부분의 언어에서 =은 할당문을 나타낸다. 그러나 얼랭에서 =는 패턴 매칭 연산을 뜻한다. Lhs = Rhs 가 진짜로 의미하는 바는 오른쪽(Rhs)를 계산한 다음, 그 결과를 왼쪽(Lhs)에 있는 패턴과 매치하라는 뜻이다.

 

부동 소수점 수

부동 소수점 수는 소수점에 이어 적어도 하나의 소수가 와야 한다. 정수 두 개를 ‘/’로 나누면 그 결과는 자동으로 부동 소수점 수로 변환된다.

 

애텀

얼랭에서 애텀(Atom)은 수치가 아닌 상이한 불변 값을 나타내는 데 사용한다.

얼랭에서 애텀은 전역(global)이며, 또한 매크로 정의나 인클루드 파일을 사용하지 않고도 그 목적을 달성할 수 있다.
애텀은 소문자로 시작하고 그 뒤로 일련의 알파뉴머릭(alphanumeric)문자나 언더스코어(_) 또는 at(@) 기호가 온다.

애텀은 작은 따옴표(‘ ‘)로 묶을 수 있다. 인용 부호 형태를 사용하면 대문자로 시작하는 애텀(그러지 않으면 변수로 해석되었을 것이다)이나 또는 알파뉴머릭이 아닌 문자가 들어간 애텀을 만들 수 있다. 예를 들면, ‘Monday’, ‘Tuesday’, ‘+’, ‘*’, ‘an atom with spaces’ 와 같은 것들이다. 인용부호를 사용할 필요가 없는 애텀들도 묶을 수 있으며, 따라서 ‘a’는 a 와 정확히 똑같다.

애텀의 값은 애텀일 뿐이다. 그저 애텀인 명령을 주면 얼랭 셸은 그 애텀의 값을 출력할 것이다.

15> hi.
hi

애텀의 값 또는 정수의 값이라는 말이 다소 이상해 보일 수도 있다. 그렇지만 얼랭이 함수형 언어인 까닭에, 모든 식은 값을 가져야 한다. 아주 간단한 식인 정수와 애텀도 예외는 아니다.

 

 튜플

정해진 수의 항목을 하나의 개체로 그룹핑한다고 해보자. 이럴 때 튜플(Tuple)을 사용한다. 튜플은 여러분이 표현하고자 하는 값들을 중괄호로 둘러싸고 쉼표로 그 값들을 구분하면 된다.

튜플은 C의 구조체와 유사하다. 다른 점이라면 튜플은 익명이라는 것이다. 얼랭에는 형 선언이 없기 때문에, ‘점(point)’를 만들 때는 다음과 같이 작성하면 된다.

16> T = {10, 45}.
{10,45}
17> T .
{10,45}

이러면 튜플을 하나 생성하여 그것을 변수 P와 묶는다. 튜플의 필드는 이름이 없다. 튜플 그 자체는 그저 정수 한 쌍만 들어 있을 뿐이므로, 그게 어떤 용도로 사용되는지는 우리가 기억해야 한다. 튜플이 어디에 사용되는지 기억하기 쉽도록 하려고, 통상 튜플의 첫 번째 요소로 그 튜플이 무엇인지를 나타내는 애텀을 사용한다. 또한 튜플은 중첩될 수 있다.

 

튜플 생성하기

튜플은 선언할 때 자동으로 생성되고 더는 사용되지 않을 때 제거된다. 얼랭은 가비지 콜렉터(garbage collector)를 사용하여 사용되지 않는 모든 메모리를 수거하기 때문에 우리가 메모리 할당에 대해서 걱정할 필요는 없다.

새 튜플을 구성할 때 변수를 사용하면, 그 새 튜플은 변수가 참조하는 데이터 구조의 값을 공유할 것이다.

2> F = {firstName, jonathan}.
{firstName,jonathan}
3> L = {lastName, kim}.
{lastName,kim}
4> P = {person, F, L}.
{person,{firstName,jonathan},{lastName,kim}}

만약 정의되지 않은 변수로 데이터 구조를 생성하려 하면 오류가 날 것이다.

 

 튜플에서 값 추출하기

마치 할당문처럼 보이는 ‘=’는 얼랭에서는 할당문이 아니라 패턴 매칭 연산자이다. 사실, 패턴 매칭은 얼랭의 근본이며 많은 다양한 작업에서 사용된다. 패턴 매칭은 데이터 구조에서 값을 추출해내는 데도 사용되고, 함수 속의 제어 흐름이나, 병렬 프로그램에서 어떤 프로세스로 메시지를 보낼 때 어느 메시지가 처리되어야 하는지를 정하는 데도 사용된다.

튜플에서 어떤 값을 추출하려면, 패턴 매칭 연산자 ‘=’을 사용한다.

5> Point = {point, 10, 45}.
{point,10,45}
6> {point, X, Y} = Point.
{point,10,45}
7> X.
10
8> Y.
45

위의 예에서와 같이, 등호 표시의 양쪽에 있는 튜플은 요소의 개수가 같아야 하며, 양측의 대응되는 요소는 같은 값으로 바인드되어야 한다.

복잡한 튜플인 경우, 그 튜플과 똑같은 모양(구조)으로 된 패턴을 하나 만들고 그 패턴 속에서 사용자가 값을 추출하고자 하는 곳에 언바운드 변수를 둠으로써 값을 추출해낼 수 있다.

 

리스트

개수가 가변적인 무엇인가를 저장할 때는 리스트(List)를 사용한다. 리스트는 요소를 대괄호로 둘러싸고 쉼표로 요소들을 구분하여 만든다.

 

 리스트 – 용어

리스트의 첫째 요소를 그 리스트의 ‘헤드(head)’라고 부른다. 리스트에서 헤드를 제거했을 때, 남은 부분을 가리켜 그 리스트의 ‘꼬리(tail)’라고 부른다. 리스트의 헤드는 무엇이든 될 수 있지만, 꼬리는 통상적으로 리스트라는 점에 유의하자.

리스트의 헤드를 액세스하는 것은 매우 효율적인 연산이기 때문에 사실상 모든 리스트 처리 함수가 리스트의 헤드를 추출하는 것에서 시작한다. 리스트의 헤드에 대해 뭔가를 하고, 리스트의 꼬리를 처리하는 식이다.

 

 리스트 – 정의하기

T가 리스트이면, [H|T]도 리스트다. 헤드가 H이고 꼬리가 T인 리스트인 것이다. 세로막대 |는 리스트의 헤드와 꼬리를 구분한다. []는 빈 리스트이다.

[…|T] 생성자를 사용하여 리스트를 만들 때는 T가 리스트임을 보장해야 한다. 그러면 새 리스트는 적절한 형태가 될 것이다. 만약 T가 리스트가 아닐 경우, 그 새로운 리스트는 부적절한 리스트라 부른다. 대부분의 라이브러리 함수들은 리스트가 적절한 형태임을 가정하기 때문에 부적절한 리스트와는 작동하지 않는다.

 

 리스트 – 요소 추출하기

다른 모든 것과 마찬가지로, 리스트에서 요소를 추출하는 데도 패턴 매칭 연산을 사용할 수 있다.비어 있지 않은 리스트 L 이 있다면, 식 [X|Y] = L (이때 X와 Y는 언바운드 변수다)은 리스트의 헤드를 X에 그리고 리스트의 꼬리를 Y로 추출할 것이다.

 

 문자열

엄밀히 말하면, 얼랭에는 문자열이 없다. 문자열(string)은 실제로는 정수의 리스트일 따름이다. 문자열은 큰따옴표(“”)로 둘러싼다.
어떤 프로그래밍 언어에서는 문자열은 작은따옴표 또는 큰따옴표로 묶을 수 있지만 얼랭에서는 큰따옴표를 사용해야 한다.

셸에서 리스트의 값을 출력할 때는 리스트를 문자열로 출력하는데, 그건 오직 그 리스트 속에 있는 모든 정수가 출력 가능한 문자들을 나타내는 경우에 한해서다.

어떤 정수가 어떤 문자를 표현하는지 알 필요는 없다. 알아야 한다면, ‘달러 구문(dollar syntax)’을 사용하면 된다.

 

 문자열에서 사용하는 문자집합

문자열의 문자들은 Latin-1 (ISO-8859-1)문자 코드를 표현한다.

Chapter 1. 연습문제

 1. CPU의 관점에서 원하는 곳으로 패치시킨다는 것과 가장 관련 있는 CPU의 레지스터는 무엇인가?
-> CPU의 관점에서 바라본 “원하는 곳으로 패치(Fetch) 시킨다”는 것은 현재 실행하고 있는 명령 다음에 어떤 명령을 실행시킬 것인가와 관련이 깊다. 따라서 다음번 명령어의 주소값을 저장하고 있는 PC(Program Counter) 레지스터이다.

 2. 네트워크 관점에서 원하는 곳으로 패치(Fetch)시킨다는 용어는 무엇에 해당하겠는가?
-> 네트워크 관점에서의 패치는 패킷을 전송하는 것과 같은 의미를 가진다고 이야기 할 수 있다. 이중에서도 “원하는 곳으로 패치”한다는 것은 본래의 목적과는 다른 곳으로 패킷을 전송시킨다는 것으로 이야기할 수도 있을 것이다. 패킷을 캡쳐해서 해당 패킷의 목적지를 원하는 목적지로 변경하는 등의 여러 방법이 있겠지만 대표적인 것으로 패킷 스푸핑이 있을 수 있다.

 3. 튜링이 ‘계산하는 기계”에게 시켜 증명하고자 했던 것은 무엇이었는가?
-> 판정문제를 증명하고자 했다.

 판정문제

 계산 가능성 이론계산 복잡도 이론에서 판정 문제란 어떤 형식 체계에서 예-아니오 답이 있는 질문을 말한다. 결정 문제라고도 한다. 예를 들어 “두 숫자 xy가 있을 때 yx로 나누어 떨어지는가?” 하는 질문이 있다. 답은 xy 값에 따라 ‘예’ 또는 ‘아니오’ 중 하나가 될 수 있다.

판정 문제를 푸는 데 쓰인 방법을 알고리즘이라고 한다. 어떤 판정 문제를 푸는 알고리즘이 있으면 그 문제는 판정 가능하다고 한다. 없으면 판정 불가능하다고 한다.

 
 4. 현재도 쓰이고 있는 일반 전화 시스템(PSTN, Public Switched Telephone Network)은 음성(Voice)뿐만 아니라 누르는 전화번호 같은 데이터(Data)도 사람이 들을 수 있는 가청 주파수로 보낸다. 존 드라퍼가 공개한 전화 해킹(Phone Phreaking)은 장거리 전화 관련 신호를 전송하던 주파수인 2,600Hz에 잡음을 주어 교환기를 교란시키는 방법이었다. 이것이 가능한 것은 2,600Hz 가 수화를 통해 들을 수도 있고 보낼 수도 있는 가청 주파수이기 때문이다. 이런 구조이기 때문에 만약 전화를 거는 곳이 시끄러운 곳이라면 전화번호를 누를 때 주위의 잡음 영향을 받기가 쉬워 전화번호가 제대로 전달되지 않을 가능성이 크다. 이 같은 취약점을 막기 위해서 전화기는 전화번호를 교환기에게 어떤 방식으로 전달하는가?

-> 전화기에서 교환기로 전화번호를 전달하는 방식은 크게 두가지로 나눌 수 있다.
 DP 방식과 PB 방식이 그것이다.
 DP 방식
 DP방식은 다이얼 인 펄스(Dial in pulse) 신호의 전달 속도에 따라 10PPS(1초간에 10펄스를 발생)와 20PPS(1초간에 20펄스를 발생) 두 종류가 있다. 1 PPS는 1초간에 1개 펄스를 내는 것을 말한다. 우리나라는 20 PPS를 사용하고 있다.

 PB방식
 PB방식 다이얼 신호는 7개의 주파수 종류 중 2개 주파수의 조합으로 만들어진다. 즉, 음성대역내의 높은 3개 주파수(1209, 1336, 1447Hz)와 낮은 4개 주파수(697, 770, 852, 941Hz) 중 각각으로부터 하나의 주파수를 선정, 이를 조합해서 0에서 9까지의 숫자와 *와 #의 기능 부호로 전화를 거는 것이다.

이부분…쉽지 않다.. 두개의 주파수를 조합해서 사용한다??? 나중에 다시..

 5. 1장에서는 기술발전트리 상단부의 위치에 있을수록 더 좋다는 논리를 폈다. 기술 발전 트리 상단부에 있는 기술자에 대해 상대적으로 트리 하단부에 있는 기술자가 항변할 수 있는 논거를 대보자.
 -> 실생활에 기술접목을 쉽게 할 수 있다. 즉, 기술의 응용력과 적용력이 상단부에 비해 엄청난 힘을 발휘한다.

insert_iterator 반복자 활용

 입력 반복자를 이용하여 노드를 삽입시 많이 사용되는 반복자가 insert_iterator이다. 이 반복자를 이용하면 원하는 위치에 노드를 삽입하려 할 때 편하게 작업을 수행할 수 있다. 반복자의 사용 예를 보면 다음과 같다.

#include <iostream>
#include <list>

using namespace std;

int main()
{
  // 스트링을 저장할 리스트 선언 및 첫 번째 스트링 저장
  list<string> strList;
  strList.push_back(“AAA”);

  // 리스트에 데이터를 입력하기 위한 반복자 선언
  insert_iterator<list<string> > listIter(strList, strList.begin());

  // 반복자를 이용한 노드 삽입
  *listIter++ = “EEE”;
  *listIter++ = “DDD”;
  *listIter++ = “CCC”;
  *listIter++ = “BBB”;

  // 출력 반복자와 출력 스트림을 이용하여 화면 출력
  copy(strList.begin(), strList.end(), ostream_iterator<string>(cout, ” “));
}

 예제를 실행하면 EEE ~ BBB 순으로 노드가 저장된 것을 확인할 수 있다.

리스트

 리스트는 순차형 컨테이너이면서 포인터 연산을 수행하기 때문에 특정 노드를 바로 찾아가는 키의 개념이 없다. 따라서 원하는 노드를 찾고자 할 때는 반복자를 이용하여 처음부터 차례대로 노드들을 체크해보아야 한다. 리스트는 이러한 단점에도 불구하고 인의의 노드의 삽입과 삭제가 무척 빠르고 효율적이기 때문에 활용가치가 무척 높은 자료구조이다.

벡터

 벡터는 원소의 상수 레퍼런스를 반환하는 메소드를 제공한다. 이 메소드를 이용하면 벡터 속에 있는 데이터를 바로 얻을 수 있다. 이러한 메소드에는 front(), back() 등이 있다.

 다음은 front()와 back() 메소드의 간단한 사용 예를 보여주고 있다.

strVec.push_back(“A”);  // 벡터 내부: A
strVec.push_back(“B”);  // 벡터 내부: A B
strVec.push_back(“C”);  // 벡터 내부: A B C

cout << “시작: ” << strVec.front() << “, 끝: ” << strVec.back() << endl;

 이 문장을 실행시키면 A와 C의 데이터가 화면에 출력된다.