오늘날 기계와 의사소통하는 방법은 퍽 쉽다.
“노래를 틀어달라”고 말하면 인공지능이 통역해준다.
프로그래밍 언어를 배우면 컴퓨터에 ‘편지’를 쓸 수도 있다.
그런데 편지를 채울 글과 규칙이 개발되기 전에는 컴퓨터의 언어인 0과 1을 읽고 쓸 수 있어야 했다. 두 개의 신호는 전선을 바느질해 기계로 입력됐다. 세계 공용어인 영어만큼이나 프로그래밍 언어가 중요해진 시대, 프로그래밍 언어의 시작과 발전을 살펴봤다.
닭이 먼저, 달걀이 먼저? 언어가 먼저!
“KAIST 전산학부를 졸업하면 프로그래밍 언어를 몇 개나 배우나요?”
기자의 질문에 류석영 KAIST 전산학부 교수는 “8개 정도”라고 대답했다. 첫 해에 Python(파이썬), 두 번째 해엔 Java(자바)와 C를, 이후 Rust(러스트), Scala(스칼라), OCaml(오캐믈) 등을 배운다. 영어영문학과에서는 영어만, 중어중문학과에서는 중국어만 배우는 것과 비교하면 왠지 억울하게 들린다.
하지만 어쩔 수 없는 일이다. 컴퓨터와 얘기하는 방법이 여러 가지기 때문이다. 프로그래밍 언어가 정확히 몇 개인지 아는 사람은 아무도 없다. 프로그래밍 언어는 누구나 만들 수 있기 때문이다. 설령 발명자조차 쓰지 않아도.
개발 현장에서 사용하는 언어도 다양하다. 언어의 고유한 기능과 특성에 따라 적합한 분야가 달라서다. 또 프로그래밍 언어는 배포된 이후에도 개발자들의 요구에 맞춰 끊임없이 버전 업데이트를 해 고정적이지 않다. 발전한 기술에 적합한 소프트웨어를 개발하기 위해 프로그래밍 언어를 새로 만들기도 한다. 이 모든 노력은 우리가 소통하기 원하는 대상이 바로 기계라는 점에서 출발한다.
컴퓨터는 특별한 기계다. 영국의 수학자이자 컴퓨터공학자인 앨런 튜링은 컴퓨터를 ‘보편 만능 기계’라 표현했다. 하나의 기계가 모든 일을 할 수 있기 때문이다. 오늘날 컴퓨터는 더 많은 일을 할 수 있고, 관련이 없을 것 같던 냉장고 같은 기계에도 들어가 작동한다.
컴퓨터를 보편 만능 기계로 만든 건 소프트웨어다. 소프트웨어는 인간이 컴퓨터를 구동하는 방법이자, 컴퓨터가 실행되는 방법이다. 그리고 이 소프트웨어를 만드는 작업이 곧 인간이 기계와 의사소통을 하는 일이다. 소프트웨어를 만드는 작업을 프로그래밍이라 부른다. 즉 프로그래밍 언어는 소프트웨어를 만들 때 사용하는 의사소통 도구다. 재밌는 점은 의사소통 도구가 컴퓨터보다 먼저 고안됐다는 것이다. 어떤 명령을 이해하고 동작하는 실행기인 컴퓨터는 1940년대 후반, 영국의 앨런 튜링과 미국의 존 폰 노이만에 의해 각각 설계됐다. 그런데 언어의 시작은 그보다 10여 년 더 빨랐다.
87년 전, 수학계가 쏘아 올린 거대한 공
프로그래밍 언어는 두 개의 뿌리가 있다. 하나는 ‘튜링 기계’ 또 하나는 ‘람다 계산법’이다. 두 개의 뿌리는 같은 질문에서 나왔다. 당시 유럽 수학계가 쏘아 올린 거대한 공이었다.
수학자이자 컴퓨터공학자인 튜링은 1936년, 자신의 논문 ‘계산 가능한 수에 대해, 수리명제 자동판별 문제에 응용하면서’에서 최초로 컴퓨터에 대한 설계도를 그렸다. 이 최초의 컴퓨터는 ‘튜링 기계’라 불린다. 튜링 기계는 당시 유럽 수학계의 가장 큰 이슈였던 ‘몇 개의 추론 규칙을 찾아낸다면, 앞으로 수학자들이 증명해야 할 모든 명제를 쉽게 찾을 수 있다’는 주장을 부정하기 위해 만들어졌다.
해당 주장은 1928년, 독일의 수학자 다비트 힐베르트가 세계수학자대회에서 공식적으로 제기했다. 이광근 서울대 컴퓨터공학부 교수는 “이 주장에서 ‘모든’이란 단어와 ‘쉽게’란 단어에 주목해야 한다”고 조언했다. 힐베르트의 주장이 참이라면 모든 수학적 문제를 기계적인 계산으로 환원할 수 있다는 결론이 나오기 때문이다. 그런데 1931년 미국의 수학자 쿠르트 괴델이 ‘불완전성의 정리’를 발표해 ‘기계적인 방식으로 수학의 모든 사실을 만드는 것은 불가능하다’는 명제를 증명해내며 힐베르트의 주장을 부정했다.
튜링은 괴델의 ‘불완전성 정리’에 대한 증명을 자신의 방식으로 풀어냈다. 이것이 튜링 기계가 고안된 바로 그 논문이다. 튜링은 풀이과정에서 기계적인 계산이 무엇인지 명확히 정의해야 했고 그 정의가 튜링 기계였다.
같은 시대 바다 건너 미국 대륙에서도 또 다른 언어의 기원이 만들어졌다. 주인공은 미국의 논리학자이자 수학자인 알론조 처치였다. 처치는 모든 수학을 기계적인 계산으로 풀어낼 수 있다는 힐베르트의 주장을 듣고 튜링과 마찬가지로 기계적으로 계산한다는 것의 정의를 정하고 싶었다. 처치는 그 정의로 람다 계산법(Lambda calculus)을 제안했다.
주류가 된 튜링 vs. 비주류의 람다
더 크게 자란 것은 튜링 기계에 뿌리를 둔 언어였다. 일명 ‘기계에 명령하는 언어’다. 튜링 기계는 총 5개의 구성 요소로 이뤄져있다. 무한히 많은 칸을 가진 테이프와 테이프에 기록되는 기호, 기록된 기호를 읽거나 쓰는 장치, 장치의 상태를 나타내는 기호, 마지막으로 기계의 작동규칙표다. 이 중 작동규칙표가 튜링 기계에 뿌리를 둔 언어의 기원이다. 튜링 기계가 맺은 열매는 C, 자바, C++, C#, JavaScript(자바스크립트) 등 오늘날 개발 현장에서 많이 사용하는 주요 언어들이다.
한편 람다 계산법에서 기계는 안중에도 없다. 오직 값을 갖고 새로운 값을 계산하는 상위의 언어일 뿐이다. 그런데 람다 계산식 하나가 곧 기계적으로 작동하는 프로그램을 하나 만드는 명령과 같았다.
이 교수는 “람다 계산법 관점으로 프로그래밍을 바라보면 언어와 논리는 동전의 양면일 뿐, 같은 것”이라고 설명했다. 언어, 즉 계산식으로 짠 프로그램과 논리로 짠 증명이 일대일 대응이 된다는 것이다. 이는 논리학자들이 어떤 증명을 만들고, 검토하고, 수정하는 과정이 프로그래밍과 똑같다는 뜻이다.
처치는 기계에 대한 생각은 하지 않았지만, 람다 계산법은 ‘튜링-완전(turing-complete)’한 언어다. 튜링-완전하다는 것은 프로그래밍 언어로 기계적인 계산은 뭐든 표현할 수 있다는 의미다. 때문에 이 교수는 “튜링 기계와 람다 계산법이 결론적으로 똑같다”고 말한다. 컴퓨터로 돌릴 수 있는 모든 소프트웨어를 표현할 수 있는 언어기 때문이다. 다만 프로그래밍 언어가 확장되는 과정에서 람다 계산법을 토대로 개발된 언어는 튜링 기계 기반 언어에 비해 주류는 아니었다. 대표적으로 Standard ML, 오캐믈, Haskell(하스켈), F# 등이 있다.
기계만 편한 1,2세대 ‘저급 언어’
튜링 기계 기반의 초창기 프로그래밍 언어는 컴퓨터에게만 편한 언어였다. 1세대 프로그래밍언어는 ‘기계 언어(machine language)’라 불린다. 2진수 형태로 0과 1로 표현하는 언어였다. 이 언어는 컴퓨터가 직접 이해하고 실행할 수 있는 언어다. 물론 컴퓨터가 실제 숫자를 이해하는 것은 아니다. 0과 1은 전기 신호의 있고 없음을 나타낼 뿐이다. 때문에 언어를 따로 번역하는 절차가 필요없었다.
기계 언어는 호환성도 없다. 특정 명령문을 기계 언어로 바꿔 하나의 CPU를 실행시킨 뒤, 같은 명령문을 다른 제조사에서 만든 CPU에 입력하면 동작하지 않는다. 같은 제조사가 만든 CPU라고 하더라도 버전이 다르면 다른 기계 언어에 동작한다. 이는 CPU가 ‘어떤 언어’를 이해해 실행하는 실행기일 뿐, ‘어떤 언어’가 무엇인지는 생산 과정에서 다르게 정의되기 때문이다.
이후 2진수가 아닌 16진수로 변환한 기계어가 개발됐지만 마찬가지로 인간이 사용하기엔 어렵고 복잡했다. 2진수를 16진수로 변환하면 코드의 길이가 짧아지는 장점만 있을 뿐이었다. 현재의 개발자들은 컴퓨터와 의사소통을 하기 위해 더는 기계 언어를 사용하지 않지만 아직도 컴퓨터에서 사용하는 명령어 집합이 기계 언어의 형태로 제공된다.
인간은 이후 알파벳을 활용한 2세대 프로그래밍 언어, 어셈블리어를 만들어냈다. 어셈블리어는 기계 언어와 일대일 대응이 되는 기호로 이뤄진 언어다. 특히 이동과 덧셈, 뺄셈과 같은 연산이 특정한 기호로 정리됐다. 이 기호 코드 덕분에 어셈블리어는 기계 언어에 비해 좀 더 인간이 쓰기 편했고, 또 코드를 이해하기 쉬웠다.
기계 언어와 마찬가지로 어셈블리어도 사멸한 것은 아니다. 기계어와 어셈블리어를 통칭하는 ‘저급(Low-Level) 언어’는 컴퓨터가 명령을 받아들이는 속도가 빨라, 즉각적인 실행을 요하는 프로그램에서는 여전히 어셈블리어를 쓰고 있다. 특히 시스템 해킹이나 컴퓨터 구조를 연구할 때 어셈블리어가 사용된다.
인간에 가까워진 ‘고급 언어’
컴퓨터가 널리 보급되기 시작하면서 더 많은 인간이 소프트웨어를 만들고 이해하고자 했다. 그렇게 3세대 프로그래밍 언어가 1950년대에 처음 개발됐다. Fortran(포트란)과 COBOL(코볼)이 그 주인공이다. 3세대 이후 언어부터 ‘고급(High-Level) 언어’라 칭한다. 사람 중심의 언어가 시작된 것이다.
사람 중심의 언어는 번역기와 함께 시작됐다. 인간과 컴퓨터 사이의 번역기는 ‘컴파일러’라고 부른다. 오늘날 우리가 컴퓨터에 고급 언어를 입력하면 컴파일러가 컴퓨터가 이해할 수 있는 기계어로 변환한다.
오늘날 프로그래밍 언어는 정해진 문법 구조와 형식, 뜻 그리고 구성 요소로 짜여진 한 줄, 혹은 1000만 줄의 편지가 됐다. 언어의 문법과 의미구조를 이해한다면 누구든 보고 읽고 또 쓸 수 있다. 편의성을 높인 고급 언어는 나무에 줄기가 여러 갈래로 뻗어 나가듯 다양한 지향을 갖고 발전해 나갔다.
실수 줄이려 다시 만난 세계, 람다와 튜링
1962년 7월, 미국항공우주국(NASA)은 미국 최초의 행성 탐사선, 마리너 1호를 발사했다. 마리너 1호의 임무는 금성을 지나 화성을 거쳐 수성까지 갔다가 돌아오는 것이었다. 마리너 1호에는 ‘코어 루프 메모리’가 탑재돼 있었다. 코어 루프 메모리는 도넛 모양 코어에 구리 선을 통과시키거나 통과시키지 않는 ‘바느질’로 0과 1의 신호를 입력해야 했다. 바느질에 능숙한 미국 여성 노동자들이 한 땀 한 땀 구리선을 꿰어 만들었기에 ‘리틀 올드 레이디(Little Old Lady) 메모리’라고도 불렸다.
그런데 마리너 1호는 수성까지 가기는 커녕, 발사 4분 만에 파괴됐다. 비행 시스템의 코드 에러 때문이었다. 당시 마리너 1호의 소프트웨어는 포트란으로 썼는데, 코드에서 하이픈(-)이 하나 누락됐다. 별 거 아닌 것처럼 보이는 기호의 누락은 우주선에 잘못된 안내 신호를 전송하는 결과로 이어졌다. 큰 꿈을 안고 올라간 탐사선은 작은 실수 하나로 산산이 조각나 낙하했다.
개발자들은 이 같은 실수를 최소화할 수 있는 프로그래밍 언어를 개발하고자 했다. 덕분에 프로그래밍 언어는 복잡한 소프트웨어를 실수 없이 잘 만들기 위한 방향으로 발전했다. 한 예로 타입 검사 시스템이 언어에 구현되기 시작했다. 타입 검사란 입력 받는 데이터의 유형이 올바른 지를 언어 차원에서 확인하는 시스템이다.
실수를 최소화하려는 과정 속, 튜링 기계에서 출발한 프로그래밍 언어와 람다 계산법에서 출발한 프로그래밍 언어가 자연스럽게 합쳐졌다. 자바와 스칼라가 대표적이다. 1991년 튜링 기계에 기반해 개발됐던 자바는 2014년 3월 발표된 버전 8부터 람다 계산법을 적용했다. 2004년에 개발된 스칼라는 처음부터 튜링 기계의 특징과 람다 계산법을 염두에 두고 설계됐다.
류석영 교수는 “자바와 스칼라 두 언어 모두 튜링 기계를 뿌리로 발전한 객체 지향 언어인데, 함수형 프로그래밍 언어의 장점이 잘 버무러져 있다”고 설명했다.
람다 계산법에 뿌리를 둔 함수형 프로그래밍 언어는 논리학의 성과를 적극 수용했다. 논리학에서 명제를 치밀하고 탄탄하게 증명하는 방법을 프로그래밍 언어에 녹였다. 그 결과 오캐믈, 하스켈과 같이 함수형 언어는 믿을 만한 타입 검사 시스템이 구현돼 안전하다. 전문가들이 ‘좋은’ 언어라고 평가하는 이유다.
지구와 컴퓨터의 공생을 위하여
프로그래밍 언어는 앞으로 어떻게 발전해 나갈까. 우선은 현재까지 닦아온 길을 더 열심히 닦아야 한다. 이 교수는 “문제 없는 소프트웨어를 만들기 위해서는 타입 검사 시스템이 더 정교해져야 한다”고 말했다.
프로그래밍 언어가 어떤 사회적 의미를 가지는지도 생각해봐야 한다. 류 교수는 “오늘날 소프트웨어는 많은 데이터와 큰 계산능력을 요구한다”며 “이런 거대 컴퓨팅 파워가 특정 국가와 특정 기업에 몰리고 있다”고 우려했다. 소프트웨어적 자산이 독점화되는 상황이라는 것이다. 또 거대화된 소프트웨어는 탄소를 대규모로 배출할 수 있다. 류 교수는 “기후변화에 컴퓨터과학도 책임을 져야한다”며 “지속가능성과 민주주의가 프로그래밍 언어 개발에 주요 가치로 상정돼야 한다”고 말했다.
프로그래밍 언어는 ‘일방 소통’인 까닭에 원하는 것이 있으면 목표에 도달하는 방법까지 고안해 언어에 녹여야 한다. 앞으로 더 많은 언어가 새로운 기술을 안고 생겨날 것이다.