[clearfix]
1. 개요
APL은 1960년대에 만들어진 배열(array) 지향, 함수형 언어이다. A Programming Language의 약자를 따서 APL이라고도 부른다. 여기서 a는 정관사라고 한다. 그러니까 프로그래밍 언어 이름이 '프로그래밍 언어'(...)인 것이다. 물론 진짜 A언어(후에 A+로 개명)도 나오긴 했는데 이 APL의 구현체 중 하나였다.2. 특징
2.1. 복잡함
이 언어는 여러 가지 특수문자로 이루어져 이해하기 어렵다. 현재 키보드로는 입력을 못하는 수준이다. 하지만 그 당시 대기업이었던 IBM이 지원했던 탓에 전용 키보드도 나왔다.
그 복잡성은 악명이 높았는지 이런 시도 있다.
`Tis the dream of each programmer
Before his life is done
to write three lines of APL
And make the damn thing run
그것은 모든 프로그래머의 꿈이라네
그의 삶이 다하기 전에
세 줄의 APL 코드를 짜고
그 망할 코드가 실행되게 하는 것
Fun_People Archive - 8 Nov
APL은 흔히 난해한 프로그래밍 언어로 알려져 있다. 그러나 APL이 한국어 '난해한 프로그래밍 언어'의 정의에는 부합하지만 지적 유희를 위해 만든 언어는 아니므로 Esoteric programming language가 아닌 Write-only language(코드를 처음부터 작성하는 건 쉽지만 기존 코드를 읽고 유지보수하기는 매우 어려운 언어)에 해당하며, APL이 이 단어가 가리키는 대상의 대표적이고 교과서적인 예시라 할 수 있다.Before his life is done
to write three lines of APL
And make the damn thing run
그것은 모든 프로그래머의 꿈이라네
그의 삶이 다하기 전에
세 줄의 APL 코드를 짜고
그 망할 코드가 실행되게 하는 것
Fun_People Archive - 8 Nov
2.2. 간결함
그럼 이렇게 복잡해 보이기만 하는 언어를 어디다 쓰냐면, 이러한 특수 기호가 사용되고 함수형 언어이기도 해서 코드가 극단적으로 간결해져 코드 골프가 가능하다. 아래는 로또 6/45처럼 1부터 45까지의 자연수 중 6개를 랜덤으로 뽑은 다음 오름차순 정렬을 해서 출력하는 코드이다. x[⍋x←6?45]
특수 기호를 3바이트로 계산해도 14바이트밖에 안 된다.APL의 함수는 명시된 인수가 없이 여러 기본 함수(primitives)들을 합성하여 하나의 함수로 만드는 방식을 사용한다. 이를 무인수 프로그래밍, 또는 Tacit programming이라 부른다. 벡터의 각각의 값이 벡터 전체의 평균 이상인지 판별하는 함수를 만들고 싶다고 치자. 산술평균을 구하는 가장 일반적인 방식은 벡터의 값을 다 합친 다음 원소 개수대로 나누는 것이다.
- 연산자
f⌿x
는 fold 연산자이다.+⌿x
의 경우는 벡터x
의 값의 합을 구한다. - 단항함수
≢x
는 벡터x
의 원소 수를 구한다. - 그러므로
+⌿÷≢
는 벡터x
의 산술평균을 구해 준다. - 함수
⊢
는 함수의 오른쪽 인자를 반환한다. - 이항함수
>
는 함수의 왼쪽 인자와 오른쪽 인자를 비교하여, 왼쪽 인자가 크다면 1, 아니면 0을 반환한다. - 여러 함수와 연산자로 된 train을 괄호로 감싸면 하나의 함수로 취급한다.
(⊢>+⌿÷≢)x
자연어로 치자면 한문에 비유할 수 있는데 외워야 할 글자가 많지만 그에 비해 문법이 간결하다는 것이 공통된 특징이다.3. 문법
연산은 오른쪽에서 왼쪽으로 실행된다. 예를 들어,2×3+4
라는 코드가 있다면, 다른 프로그래밍 언어에서는 곱하기가 더하기보다 우선순위가 높기에 곱하기를 먼저 계산하여 10을 내놓지만, APL은 가장 오른쪽의 더하기를 먼저 계산하여 14를 내놓는다.3.1. 함수와 연산자
APL에서는 자료를 인자로 받는 것은 함수, 함수를 인자로 받는 것을 연산자라고 부른다. 따라서 다른 언어들에서 연산자로 불리는 +, -, ×, ÷ 등은 APL에서는 모두 함수이다.함수는 단항함수와 이항함수가 있으며 대부분의 함수 글리프에는 단항함수로 쓰일 때와 이항함수로 쓰일 때의 동작이 정의되어 있다.
*
를 예로 들자면, A*B
는 A의 B승을, *X
는 자연로그의 밑 e의 X승을 반환한다.3.1.1. 함수
Dyalog APL을 기준으로 한다.글리프 | 단항함수 | 이항함수 |
+ | 인자를 그대로 반환[1] | A+B |
- | 0−X | A−B |
× | 부호함수 | A×B |
÷ | 1÷X | A÷B |
\| | 절대값 | 나머지 |
⌊ | 바닥함수 | 두 인자 중 작은 값 |
⌈ | 천장함수 | 두 인자 중 큰 값 |
* | eX | AB |
⍟ | ln X | logAB |
4. 예제
- 가장 기본적인 "Hello World"를 출력하는 코드.
{{{'Hello World'
- 1부터 R까지 모든 소수를 찾는 코드.[2] 이 코드는 오른쪽에서부터 왼쪽으로 실행된다.
{{{(~R∊R∘.×R)/R←1↓ιR
- ιR : 1부터 R까지의 정수를 포함하는 벡터를 생성한다. (1, 2, 3, 4, 5, 6)
- 1↓ : 벡터의 첫번째 원소를 버린다. (함수) (2, 3, 4, 5, 6)
- R← : 벡터 R을 새 벡터로 한다. (2, 3, 4, 5, 6)
- / : 이항 감소 연산자로서, 인터프리터는 먼저 왼쪽 피연산자를 실행한다. (괄호 전체)[3]
- ∘.×R : R의 외적 행렬(outer product)을 생성한다.
4 6 8 10 12 6 9 12 15 18 8 12 16 20 24 10 15 20 25 30 12 18 24 30 36 - ∊R : 'R과 같은 길이의 벡터'를 생성하고 R의 각각의 원소가 외적 행렬에 없는 경우에는 0, 있는 경우에는 1을 입력한다. (0, 0, 1, 0, 1)
- ~R : 백터의 값에 논리 부정 연산자(~)를 적용한다. (1, 1, 0, 1, 0)
- / : 1이 입력된 자리의 R의 원소를 선택한다. (2, 3, 5)
- 행렬 X에 포함된 단어 목록을 단어의 길이에 따라 정렬하는 코드.
{{{X[⍋X+.≠' ';]
5. 현재 상황
2020년대 현재에는 사실상 쓰이지 않고 있다. 현대 프로그래밍 언어에 요구되는 특징들을 갖추고 있지 않으며, 입력에 전용 키보드가 필요할 정도로 특수한 문자 셋을 쓰는 실정도 키워드와 범용 특문을 위주로 사용하는 현대 프로그래밍 언어가 등장하고 나서는 APL을 사장시키는 데 지대한 역할을 했다. 다만 일부 메인프레임, 워크스테이션 등의 특수한 분야에서 여전히 사용되고는 있다.2020년대 현재 가장 많이 쓰이는 APL 구현체는 상용 프로그램인 Dyalog APL이다. 상용 프로그램이기 때문에 개인용으로만 무료로 쓸 수 있다. Dyalog는 멀티 패러다임을 지향하여 명령형 프로그래밍이나 객체 지향 프로그래밍까지 지원하는 한편, 명령형 프로그래밍이 기존의 함수형 프로그래밍으로 대체 가능하며 APL스럽지 못하다고 지원하지 않는 구현체도 많다.
APL의 특징인 배열 연산은 이후 프로그래밍 언어의 배열 연산 라이브러리에도 영향을 끼쳤다. 대표적으로 Python의 배열 연산 라이브러리 NumPy의 브로드캐스팅이 APL에서 유래한 것이며 NumPy의 내장함수 중에서도 APL을 연상시키는 함수가 많다.
5.1. 후속작
APL이 다양한 특수 기호를 사용하였던 데 반해, ASCII 기호를 사용한 APL 방언인 J언어가 있다. 또한 상용 데이터베이스 소프트웨어인 kdb+에서 사용하는 K언어 역시 ASCII 기호를 사용한 APL 계열 언어이다.거의 몰락한 원조 APL과 달리 위 두 APL 파생 언어들은 배열 데이터 처리가 요구되는 분야에서 범용 언어들에 밀릴지라도 가끔 쓰이고 2020년대가 된 지금에도 개발이 지속되고 있으며, 대부분의 APL 커뮤니티는 J언어와 K언어도 다루고 있다.
J언어 같은 경우 한국에도 수요가 있는지 한국어 튜토리얼도 몇 개 있다.[4]
참고로 A 다음 알파벳 글자들인 B언어나 C언어와는 전혀 관계가 없다. 이들은 명령형 언어로 A언어와는 지향점이 완전히 다르다. 반면 A언어는 명령형 구문 지원이 빈약하다.
6. 여담
7. 써 보기
[1] 복소수의 경우에는 켤레복소수[2] https://en.wikipedia.org/wiki/APL_(programming_language)[3] 연산자는 함수를 인자로 받는데 괄호로 둘러싼 코드는 그 자체로 하나의 함수로 취급한다.[4] https://wikidocs.net/book/1206