비빔을 처음 접하는 분들을 위한 튜토리얼입니다.
사실 비빔과 같은 난해한 프로그래밍 언어에서 튜토리얼 문서를 제공하는게 별다른 의미는 없을 것입니다. 그냥 세부 문법을 정의한 문서를 읽거나 예제 코드를 분석하는게 더 빠르게 비빔을 배우는 방법이기도 할 것입니다.
저는 이 튜토리얼이 비빔 문법을 학습하기 위한 시발점 역할을 하기를 바랍니다.
이 튜토리얼은 하나 이상의 프로그래밍 언어를 숙지하신 분을 대상으로 작성되었습니다.
혹시 자유롭게 구사할 수 있는 프로그래밍 언어가 없으신가요? 그렇다면, 파이썬을 배워보세요! 비록 비빔의 철학과 상반되는 언어지만 아주 좋은 언어입니다.
혹시 비빔 코드를 실행하고 싶은데, 구현체가 없나요?
Rust로 작성된 구현체인 RustBibim을 사용해보세요.
구현체를 설치할만한 환경이 안되신다구요?
RustBibim Web Demo를 통해 웹 브라우저에서 바로 사용해보세요.
비빔 문법을 더 자세히 알고싶으신가요?
문법 문서를 읽어보세요.
비빔으로 작성한 코드 예제를 보고싶으신가요?
예제 문서에 있습니다.
비빔을 다른 사람에게 홍보하고 싶으신가요?
Bibim 홈페이지를 알려주세요!
튜토리얼 문서가 필요하신가요?
지금 보고 계신 바로 이 문서입니다!
비빔은 상당히 특이한 프로그래밍 언어입니다. 비빔이 가지는 특이한 점들 중에서도 특히 두드러지는 것이 몇가지만 이야기해 봅시다.
-
공백 문자를 완전히 무시
비빔 코드는 공백 문자를 완전히 무시합니다.
다른 프로그래밍 언어들 처럼 키워드와 키워드 사이의 띄어쓰기 정도만 무시하는 것이 아닙니다.
비빔 코드에서는 공백이 정말 아무런 의미도 가지지 않습니다.
따라서 비빔 코드를 작성할 때, 공백 문자를 전혀 사용하지 않아도 되는 것은 물론이고, 공백 문자를 마구마구 뒤섞어도 좋습니다.
-
변수, 함수가 없음
비빔은 따로 변수와 함수를 선언하여 사용할 수 없습니다.
대신 다른 방법을 사용하여 다른 프로그래밍 언어의 변수와 함수가 하는 일을 대신할 수 있습니다.
-
부동소수점을 사용하지 않는 유리수
비빔에서 수를 표현할 때 사용하는 자료형은 부동소수점 표현이 아닙니다.
유리수의 정의 그대로, 기약분수로 표현합니다.
-
코드의 실행 순서가 유동적임
음, 이해하기 어려운 말이죠?
아마 이 튜토리얼이 끝날 쯤에는 이해하실 수 있게 될겁니다.
본격적으로 비빔으로 코딩하는 방법을 설명하기 전에 말씀드려야 할 슬픈 사실이 있습니다.
사실, 비빔으로 어떤 '수'를 계산하는 것은 크게 어렵지 않습니다. 그러나 그 계산 결과를 결과를 출력 하기는 매우 어렵습니다.
비빔으로 단순히 'HELLO WORLD'라는 문자열을 출력하는 코드를 작성하기 위해서는 비빔의 문법 거의 대부분을 알고 있어야 합니다. 하지만 덕분에 'HELLO WORLD' 코드를 작성할 수 있다면 비빔 문법을 거의 다 알고 있다는 뜻이지요!
따라서 우리는 앞으로 'HELLO WORLD' 코드를 분석하는 데에 대부분의 시간을 소비할 것입니다.
우선 실제 코드를 한번 볼까요?
{
[0; @:1 = {
[0; 72]
[1; 69]
[2; 76]
[3; 76]
[4; 79]
[5; 32]
[6; 87]
[7; 79]
[8; 82]
[9; 76]
[10; 68]
[11; 10]
}]
}
자, 이것이 비빔으로 작성한 'HELLO WORLD' 코드입니다.
더 정확하게는 '표준 출력으로 "HELLO WORLD"를 출력하는 코드'이지요.
아직 비빔의 문법을 설명하지 않았기 때문에, 이 코드를 보고 몇가지 짐작을 해봅시다.
'HELLO WORLD' 코드를 보면 {
문자로 시작해서 }
문자로 끝납니다. 즉, 중괄호 안에 코드 내용이 들어있습니다. 또, 그 중괄호 내부에는 다른 중괄호가 또 들어있지요.
비빔에서 중괄호는 '그릇'이라는 자료형을 표현합니다. 모든 비빔 코드는 하나의 그릇입니다.
더 자세한 내용은 나중에 다룹시다. 아직은 'HELLO WORLD' 코드를 더 살펴봐야 합니다.
더 자세히 위의 코드를 살펴보면 아주 많은 대괄호 문자가 사용된 것을 알 수 있습니다.
비빔에서는 [수; 값]
의 꼴을 가지는 코드가 아주 많이 사용됩니다. 이러한 표현식을 비빔에서는 '면발'이라고 부릅니다.
만약 좀 더 눈썰미가 있는 분이라면 '면발'들이 '그릇' 내부에 존재한다는 것을 알 수 있습니다. 이는 '그릇'은 '면발'들을 담는 역할을 하는 자료형이기 때문입니다.
여기서 우리는 위 코드를 아래와 같이 설명할 수 있습니다.
코드에는 하나의 '그릇'이 있다. 이를 그릇 root라고 하자.
그릇 root 내부에 하나의 '면발'이 들어있다. 이를 면발 a0이라고 하자.
면발 a 내부에는 내부에는 다른 '그릇' 하나가 들어있다. 이를 그릇 A라고 하자.
그릇 A 내부에는 12개의 '면발'이 들어있다. 이를 면발 b0 ~ b11라고 하자.
그럼 이를 다시 이렇게 표현할 수 있지요.
그릇 root:
면발 a0:
그릇 A:
면발 b0
면발 b1
면발 b2
면발 b3
면발 b4
면발 b5
면발 b6
면발 b7
면발 b8
면발 b9
면발 b10
면발 b11
사실, 그릇 A와 그릇 A에 담겨있는 면발 b0 ~ b11은 단순히 면발 a0에 담겨있는 내용에 불과합니다. 따라서 이는 아래의 구조로 다시 쓸 수 있지요.
그릇 root:
면발 a0:
면발 내용
그리고, 실제 일반적인 비빔의 코드는 아래와 같이 표현할 수 있습니다.
그릇 root:
면발 a0:
면발 내용
면발 a1:
면발 내용
면발 a2:
면발 내용
...
면발 an:
면발 내용
비빔의 코드는 최상위 그릇 하나에서 시작 합니다. 그리고 최상위 그릇은 여러 개의 면발을 담고 있지요.
최상위 그릇에 담겨 있는 면발들은 다양한 표현식을 담고 있습니다. 그리고 우리는 이를 '면발 내용'이라고 부릅니다.
우리는 비빔의 코드 구조를 대강 알아보았습니다. 그러나 아직 비빔의 코드를 작성하기에는 알고 있는 것이 너무 적어요. 우리가 앞으로 비빔 코드를 작성하기 위해서는 '수', '면발', '그릇'의 사용법을 먼저 익혀야 합니다.
비빔으로 하나의 프로그램을 작성하기 전에, 짧은 표현식(expression)들을 사용하면서 비빔에 익숙해져야 합니다.
앞으로 나올 코드 조각들은 그야 말로 '코드 조각'입니다. 비빔 구현체에서 실행을 할 수 없는 '코드의 일부분'일 뿐이므로, 실행해봤더니 오류가 난다고 놀라지는 마세요. 당연한겁니다.
비빔을 사용하려면 유리수랑 좀 친해져야 합니다. 비빔에서는 거의 모든 일을 유리수를 이용해서 하거든요.
비빔에서 자연수를 사용하는 것은 간단합니다. 아래의 코드 조각을 평가(evaluation)한 결과는 누구나 예상할 수 있습니다.
13
네, 위의 코드 조각을 평가하면 수 13
이 됩니다!
그럼 자연수가 아닌 정수를 만드는 것은 어떨까요? 0을 만드는 것은 자연수를 만드는 것과 같습니다.
0
위의 코드 조각을 평가하면 수 0
이 됩니다.
그럼 유리수는 어떻게 나타낼까요? 꽤나 당연한 방법으로 나타낼 수 있습니다.
1/3
위의 코드 조각을 평가하면 수 1/3
이 됩니다.
여기서 수 1/3
은 정말로 1/3입니다. 0.3333334처럼 오차를 포함한 수로 나타내는 것이 아닌 분수 1/3으로서 저장됩니다. 멋지죠?
이 예시로서 알 수 있는 꽤 인상적인 특징은, 비빔에는 나눗셈 연산자가 존재하지 않는다는 점입니다. 비빔에서 /
문자는 분수 구분자로 사용됩니다.
사실, 어떠한 유리수를 나누는 것은 결국 새로운 유리수를 하나 만드는 일과 같기 때문에 나눗셈 연산자가 존재하지 않는다는 사실은 아무 문제도 되지 않습니다. /
문자가 나눗셈 연산자가 아니라 분수 구분자라는 사실이 중요한 이유는 연산 우선순위 때문입니다.
비빔에서 분수 구분자는 다른 모든 연산자보다 연산 우선순위가 높습니다. 이 점을 확실히 기억해두세요.
수를 만들 수 있게 되었디면 이제 계산을 해봐야겠죠?
사칙연산, 그러니까 덧셈, 뺄셈, 곱셈(나눗셈은... 분수 구분자를 사용하니까 제외합니다)을 하는 방법은 예상하신 바로 그대로입니다. 각각 덧셈, 뺄셈, 곱셈에 해당하는 연산자인 +
, -
, *
를 사용할 수 있습니다.
3 + 4
위의 코드 조각을 평가하면 수 7
이 됩니다.
조금 더 복잡한 예를 들어 볼까요?
7 - 3 / 6 + 3 * 7 / 5
한번에 평가 결과를 예상하기는 어렵군요. 한 단계 한 단계씩 평가해봅시다.
가장 먼저 평가되는 것은 분수 구분자입니다. 분수 구분자의 연산 우선순위가 다른 연산자보다 높으니까요.
7 - (3 / 6) + 3 * (7 / 5)
위의 코드 조각에서 소괄호로 감싼 부분을 먼저 평가하겠지요. (비빔에서도 다른 언어들과 같이 소괄호로 감싼 부분을 먼저 가장 먼저 평가합니다.)
그 다음에 평가되는 것은 곱셈 연산자입니다.
7 - (3 / 6) + (3 * (7 / 5))
위의 코드 조각을 한 단계 평가하면,
7 - (3 / 6) + (21 / 5)
이렇게 됩니다.
이제 마지막으로 덧셈과 뺄셈을 평가합니다. 덧셈과 뺄셈의 연산 우선순위는 동일하므로, 왼쪽에서부터 차례대로 평가합니다.
따라서,
((7 - (3 / 6)) + (21 / 5))
위와 같은 코드 조각이 되고, 이를 한 단계 평가하면,
(39 / 6) + (21 / 5)
이 되고, 마지막으로 한 단계 더 평가하면(머리가 조금 아프지만),
107 / 10
이 됩니다.
비빔은 모든 유리수를 처리할 때 기약분수 로 변환하여 처리합니다.
예를 들어,
4/8
위의 코드 조각을 평가한 결과는 4/8
이 아니라 1/2
입니다.
자, 우리는 비빔에서 사용하는 수에 대한 것을 조금 배웠습니다. 이제는 비빔의 고유한 자료형인 '그릇'에 대해서 배워볼 차례입니다.
우리는 'HELLO WORLD' 코드를 처음 분석하면서 그릇에 대한 이야기를 조금 했습니다. 그 때, 그릇은 면발을 담는 자료형이라는 이야기 역시 했지요.
사실, 그릇의 역할은 정말로 그게 끝입니다. 대신 면발에 대한 이야기를 조금 더 해야겠지요.
면발은 그릇에 담기는 특별한 자료형입니다. 그릇에 대해 이야기하면서 [수; 값]
꼴로 정의된다는 이야기 역시 했었지요.
[수; 값]
표현 중에서 앞의 '수'를 우리는 '면발 번호', 뒤의 '값'을 '면발 내용'이라고 부릅니다. 즉, 면발은 '면발 번호'와 '면발 내용'의 쌍으로 이루어진 자료형입니다.
다시 그릇 이야기를 해봅시다.
그릇은 면발을 담는 자료형입니다. 다른 언어의 배열과 비슷한 역할을 하지요. 이때 면발 번호는 배열의 인덱스, 면발 내용은 배열의 값과 유사한 역할을 한다고 생각하시면 편합니다.
그럼 비빔에서도 그릇에 담겨있는 면발 내용을 가져오는 방법이 있겠죠?
비빔에서는 '그릇 참조문'을 사용해 그릇에 담겨있는 면발의 내용을 가져올 수 있습니다.
그릇 참조문은 그릇:면발번호
의 꼴로 나타냅니다. 예를 들어,
{[3; 7]}:3
위의 코드 조각을 평가한 결과는 수 7입니다.
왜냐하면, {[3; 7]}
이라는 그릇에서 면발 번호가 3
인 면발의 내용을 참조했기 때문입니다.
그럼 그릇에 담겨있는 면발 내용을 수정하는 방법도 있을까요?
물론 있습니다. 비빔에서는 '그릇 대입문'을 사용해 그릇에 담겨있는 면발의 내용을 가져올 수 있습니다.
그릇 대입문은 그릇:면발번호 = 값
의 꼴로 나타냅니다. 예를 들어,
{[3; 7]}:3 = 13
위의 코드 조각을 평가하면, {[3; 7]}
이 {[3; 13]}
처럼 바뀝니다.
그럼 한 그릇에 면발 번호가 같은 면발이 여러 개 담겨있다면 어떻게 될까요?
...딱히 아무런 일도 일어나지 않습니다. 비빔에서 그릇에 담겨있는 면발끼리 면발 번호는 같아도 실행에 문제는 없습니다.
다만, 그릇 참조문과 그릇 대입문을 수행할 때, 면발 번호가 같은 면발을 참조하려 한다면 어떤 면발이 선택될지는 며느리도 모릅니다.
자, 이제 비빔의 동작을 직접 볼 차례가 되었습니다. 이제 비빔이 코드를 어떻게 실행하는지 설명할게요.
비빔은 최상위 그릇에 담겨있는 면발 내용을 '특정한 순서대로' 평가함으로서 동작합니다.
이러한 순서는 면발 번호에 의해 결정됩니다.
비빔 코드를 실행했을 때, 가장 먼저 평가될 면발은 다음과 같은 기준으로 선택됩니다.
- 만약 면발 번호가 수
0
인 면발이 존재한다면 해당 면발을 가장 먼저 평가합니다. - 면발 번호가 수
0
인 면발이 존재하지 않는다면0
보다 크고 가장0
에 가까운 수를 면발 번호로 가지는 면발을 가장 먼저 평가합니다.
한 면발의 평가가 끝난 후, 다음 면발은 다음과 같은 기준을 모두 만족하는 면발로 선택됩니다.
- 방금 실행한 면발 번호보다 큰 면발 번호를 가집니다.
- 선택 가능한 면발 중 가장 작은 면발 번호를 가집니다.
그럼 예를 들어 봅시다.
{
[0; 내용]
[1; 내용]
[1/2; 내용]
[1/3; 내용]
}
위의 코드는 면발 번호가 0 -> 1/3 -> 1/2 -> 1
순서대로 면발이 평가됩니다.
다른 예를 들어볼까요?
{
[2; 내용]
[17; 내용]
[7; 내용]
[11; 내용]
}
위의 코드는 면발 번호가 2 -> 7 -> 11 -> 17
순서대로 면발이 평가됩니다.
이제 정말로 코드를 실행해 볼 차례가 됬습니다. 아래 코드를 한번 실행해 봅시다.
{
[0; 3 + 5]
}
위 코드는 3과 5를 더하는 코드입니다. 자, 실행 결과가 나오나요? ...아무것도 나오지 않죠? 정상입니다.
위 코드는 정상적으로 실행됩니다. 실제로 3과 5를 더하는 작업을 수행하지요. 그러나 그 결과를 우리는 볼 수 없습니다. 왜냐하면 결과를 출력시키지 않았기 때문입니다.
우리는 아직 비빔이 문자열을 출력하는 방법을 모릅니다. 따라서 실행이 되는 코드를 만들 수 있지만 그 결과를 알 수는 없지요.
좋아요, 이제 거의 다 왔습니다. 비빔에서 문자열을 읽어들이거나 출력하기 위해서는 특수 그릇인 @
(보통 골뱅이 라고 읽습니다)의 사용법을 배워야합니다.
특수 그릇 @
은 비빔에서 따로 정의하지 않아도 코드 어느 곳에서나 접근할 수 있는 특수한 그릇입니다.
비빔 프로그래머들은 특수 그릇 @
을 이용하여 아주 많은 일을 합니다. 함수 비슷한 것을 지정하기도 하고, 임시 메모리로 사용하기도 합니다.
그중에서도 특수 그릇 @
의 가장 중요한 역할이 두 가지 있습니다.
특수 그릇 @
에 면발 번호 0
을 참조하면 현재 실행중인 면발의 면발 번호를 알 수 있습니다.
이것은 매우매우 중요한 점이지만, 우리의 목표는 'HELLO WORLD' 코드를 이해하는 것이므로 지금은 설명을 생략합니다. 하지만 다른 예제 코드를 읽어보면서 이 '현재 면발 번호' 참조를 어떻게 활용했는지 꼭 확인해보세요.
특수 그릇 @
에 면발 번호 1
을 참조해서 문자열을 입력받거나 대입해서 문자열을 출력할 수 있습니다.
하지만 약간의 문제가 있습니다. 비빔에는 문자열을 위한 자료형이 없거든요.
비빔에서는 대신 그릇을 사용하여 문자열을 처리합니다.
비빔에서 그릇을 문자열로 사용할 때 하나의 그릇은 하나의 문자열로서 정의됩니다.
이 때, 그릇에 담겨있는 면발들은 한 문자를 나타내게 됩니다. 마치 다른 언어에서 문자열을 배열처럼 다루는 것 처럼 말이죠.
각 면발의 면발 번호는 0
에서부터 1
씩 증가하는 정수값을 갖습니다. 또, 면발 내용은 정수값을 가지는데, 이는 나타내고자 하는 문자의 유니코드 값입니다.
따라서, 우리는 'HELLO WORLD'라는 문자열을 비빔에서 아래와 같이 나타낼 수 있습니다.
{
[0; 72]
[1; 69]
[2; 76]
[3; 76]
[4; 79]
[5; 32]
[6; 87]
[7; 79]
[8; 82]
[9; 76]
[10; 68]
[11; 10]
}
(면발 번호가 11인 면발에 정의된 문자는 줄바꿈문자입니다.)
드디어 우리는 'HELLO WORLD' 코드를 이해하는데 필요한 모든 내용을 알아보았습니다. 그럼 다시 한번 코드를 살펴볼까요?
{
[0; @:1 = {
[0; 72]
[1; 69]
[2; 76]
[3; 76]
[4; 79]
[5; 32]
[6; 87]
[7; 79]
[8; 82]
[9; 76]
[10; 68]
[11; 10]
}]
}
'HELLO WORLD' 코드는 단 하나의 면발만 실행됩니다. 실행되는 면발 번호는 0
이고, 해당 면발의 내용은 특수 그릇 @
의 면발 번호 1
에 어떠한 그릇을 대입하는 것입니다.
특수 그릇 @
의 면발 번호 1
에 어떠한 그릇을 대입하는 것은 표준 출력으로 그릇을 문자열로서 출력하겠다는 의미입니다.
출력하는 그릇은 총 12개의 문자를 담고있으며, 이는 유니코드로 72, 69, 76, 76, 79, 32, 87, 79, 82, 76, 68, 10
입니다. 이를 실제 문자로 바꾸어보면 H, E, L, L, O, 띄어쓰기, W, O, R, L, D, 줄바꿈 문자
입니다.
따라서 위의 코드를 실행하면, 표준 출력으로 'HELLO WORLD'가 출력됩니다!
이제 이 튜토리얼은 끝입니다. 그러나 비빔에 대해 모든것을 설명한 것은 아니지요.
이 문서의 시작에도 적어놓은 링크이지만, 여기서도 다시 한 번 소개합니다.
이 튜토리얼은 비빔의 문법 일부만을 다루고 있습니다. 비빔을 재대로 사용하고 싶다면 문법 문서를 읽어보세요.
비빔 문법을 활용한 예제를 확인하는 것 역시 추천합니다.