본문 바로가기
CS 이론/🖌️ 프로그래밍 언어론

형식 언어 (Formal Language)

by 개발자 진개미 2023. 12. 17.
반응형

언어가 애초에 뭘까?

의미를 전달하기 위한 시스템

 

언어는 의미를 전달하기 위한 시스템입니다. 우리가 한국어를 할 때 결국 궁극적인 목적은 무언가를 전달하는 겁니다. 그게 지식일 수도 있고, 험담일 수도 있고, 감정일 수도 있습니다. 결국은 특정 정보/의미를 전달합니다. 이걸 아무렇게나 전달할 수 있는 것도 아닙니다. 특정 규칙에 따라서 말하고 써야 이해할 수 있습니다. 

이를 요약하면 언어에는 문법이 있고, 그 문법에 부여하는 의미가 있습니다.

 

🐜 문법 (Syntax)

우리가 처음 한글을 배우면 한글의 여러 구성 요소들을 외우게 됩니다. ㄱ, ㄴ, ㄷ, ㄹ... 이 구성 요소들이 모여서 글자 한 글자가 됩니다. 하지만 이 구성 요소들을 아무렇게나 배치한다고 글자가 되지는 않습니다. 자음 + 모음, 자음 + 모음 + 받침 등 정해진 조합에 따라 배치해야만 합니다. 이런 옳바른 언어의 구성 요소를 만드는 규칙을 문법이라고 합니다.

 

🐜 의미 (Semantic)

엄밀한 문법을 모두 맞춰서 언어를 만들더라도, 이 언어에 의미를 부여하지 않으면 그건 그냥 아무 의미도 전달할 수 없는 기호들일뿐입니다. 조현병 환자 분들이 쓴 글을 읽어 보신 적 있으신가요?

출저: 한국일보

위 글은 문법적으로만 보면 모두 맞는 표현들입니다. 한글 한 글자 글자, 단어 하나 하나는 모두 맞게 써졌습니다. 하지만 전체적인 글의 의미를 보려고 하면 굉장히 이해하기 힘들게 됩니다. (사실상 의미가 없다고 봐야겠죠) 언어의 문법만큼 중요한 게 어떤 의미를 줄 것인지입니다.


자연어와 형식언어의 차이

자연어는 인간이라는 종이 진화하면서 자연스럽게 나타난 언어입니다. 보통은 정보나 감정을 인간끼리 소통하기 위해 만들어졌습니다. 자연어는 굉장히 애매하고 계속 변합니다. 이게 꼭 나쁜건 아닙니다. 우리가 즐기는 음악이나 영화는 모두 이런 자연어의 애매함과 감정을 전달할 수 있다는 점을 살려 아름다운 작품을 만들어 냅니다.

하지만 수학이나 컴퓨터에서 자연어를 사용한다면 어떨까요? 당장 혹은/또는 (영어로는 or)을 봐도 자연어의 미칠듯한 애매함이 들어납니다. or은 크게 2가지가 있습니다.

  1. Inclusive OR
  2. Exclusive OR

우리가 보통 버스나 지하철을 타고 갈 수 있다고 하면 버스나 지하철 2개 중 1개만 탈 수 있다는 의미입니다. (Exclusive OR) 하지만 모든 상황에서 이게 명확하진 않습니다. 특히 영어에서는 더 그렇습니다.

OR은 1개의 예시일 뿐이지만 자연어에는 이런 애매한 말들과 애매한 의미들이 넘쳐납니다. 그래서 수학자들은 수학이나 프로그래밍 언어를 할 때 쓸 언어로 자연어가 아닌 엄밀한 형식 언어를 만들었습니다.

형식 언어에 대해 본격적으로 알아보기 전에 자연어와 형식 언어의 차이에 대해 짚고 넘어가겠습니다.

 

🐜 애매함

자연어는 애매합니다. 썸탈 때 상대가 한 말 하나로 계속 고민하고, 정치적 수사가 무슨 의미인지 토론하고... 이 모든 게 자연어는 1개의 명확한 의미가 있는 게 드물기 때문입니다.

하지만 형식 언어는 매우 엄밀하게 정의된 규칙에 따라 (A Well-Defined Rules) 만들어지기 때문에 굉장히 명료합니다.

 

🐜 문법의 유연함

자연어는 꼭 엄밀한 문법을 지키지 않아도 됩니다. 물론 의사 소통이 어려울 정도로 문법이 틀리면 알아듣지 못하겠지만 웬만한 상황에서는 문법이 다소 틀리더라도 큰 문제가 없고, 심지어는 특정 문법 법칙에 예외도 엄청 많이 존재합니다.

형식 언어는 문법을 엄격하게 따라야 합니다. 명확하게 정의된 문법을 1개라도 따르지 않으면 그 표현은 틀린 표현이 됩니다.

 

🐜 변화

자연어는 계속 변화합니다. 일제 강점기만 가도 한국어를 알아 듣기가 쉽지 않습니다. 우리가 쓰는 말투, 어휘, 문법 등은 시간이 지나면서 여러 영향을 받아 끊임없이 변화합니다.

반면 형식 언어는 문법와 의미가 한 번 정해지면 절대 변하지 않습니다.

 


형식언어의 구성요소

형식 요소는 자연스럽게 생겨난 게 아니라 애매함이 없는 언어를 만들겠다는 명확한 목표에서 출발했기 때문에 구성 요소가 어느 정도 정해져 있습니다. (일부는 자연어에서도 똑같이 적용됩니다.)

 

🐜 Alphabet

이 언어에서 쓸 수 있는 기호들을 모두 모아둔 게 알파벳입니다.

 

🐜 Strings

알파벳을 문법에 맞게 조합하면 String을 만들 수 있습니다.

 

🐜 Language

String들을 특정 기준에 따라 모아둔게 Language입니다.

 

🐜 Grammar

언어의 기호들을 어떻게 조합할지에 관한 규칙입니다. 촙스키 위계에 따라 4가지 종류가 있습니다. 

  1. Type 0: Unrestricted
  2. Type 1: Context-Sensitive
  3. Type 2: Context-Free
  4. Type3: Regular

형식언어에 의미 (Semantic) 부여하기

"10 이하의 숫자 2개 더하기"라는 형식 언어를 정의하고 의미를 부여해 보겠습니다!

일단 Alphabet은 이 형식 언어에 들어갈 수 있는 모든 기호들입니다. 10 이하의 모든 숫자들과 덧셈 기호, 등호 정도로 정의하면 됩니다.

Σ = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, +, = }

 

다음으로 문법 (Grammar)를 정의해 보겠습니다. 문법을 엄밀히 정의하기 위해서는 각종 어려운 표기법을 써야 하지만 여기서는 단순히 간단한 규칙을 리스트로 나열해 보겠습니다.

  • 총 5개의 부분으로 이루어진다.
  • 각 부분은 띄어쓰기로 구분된다.
  • 1번째 부분: 0-9 사이의 숫자 1개
  • 2번째 부분: +
  • 3번째 부분: 0-9 사이의 숫자 1개
  • 4번째 부분: =
  • 5번째 부분: 0-9로 이루어진 최대 2개의 숫자

참고 삼아 이걸 BNF라는 표기법으로 나타내면 아래와 같습니다.

<expr> ::= <digit> " + " <digit> " = " <result>
<digit> ::= "0" | "1" | ... | "9"
<result> ::= <digit> | <digit><digit>

 

요렇게 문법을 정의하면 String을 만들 수 있습니다. 예시로 3개 정도 만들어 보겠습니다. 위에 열거한 규칙을 모두 따라야 형식 언어에서 String이 될 수 있습니다!

  • 1 + 1 = 2
  • 1 + 1 = 0
  • 1 + 5 = 9

위의 모든 예시는 문법을 예외 없이 따른 형식 언어의 String입니다. 주의할 점은 아직 의미 (Semantic)을 부여하지 않았기 때문에 수학적으로 틀린 식도 들어갈 수 있습니다. 하지만 애초에 수학적으로 틀렸다고 하는 게 여러 의미를 가정하고 있습니다. 당장 2번째 수식은 10진수에서는 틀렸지만 2진수에서는 맞는 수식일 수도 있습니다.

 

이렇게 "10 이하의 숫자 더하기"라는 형식 언어의 문법을 애매함 없이 정의했습니다. 그렇다면 나아가서 의미 (Semantic)는 어떻게 부여할까요? 사실 위의 예제에서의 의미 부여는 굉장히 하찮은 (Trivial) 과정입니다.

모든 숫자는 수학에서의 의미 그대로 해석하고 + 또한 수학에서의 의미 그대로 해석하면 끝입니다. 엄밀히 정의한다면 집합론에서 시작해서 페아노 공리를 가져와야 하겠지만, 일반적으로 형식 언어의 추상화 수준에서 더 낮은 단계로 환원하는 작업은 그렇게 유용한 배움을 주지는 않기 때문에 생략합니다.


반응형