What makes Lisp difficult to read? or, where to put the parentheses in your next language
Lisp는 왜 읽기 어려울까요? 다음 언어에서 괄호를 어디에 둘지
Lisp의 괄호 중심 문법이 낯설게 읽히는 이유를 인지과학과 시각적 그룹화 관점에서 분석합니다. 저자는 괄호 사이 거리, 코드의 중첩과 읽는 순서가 가독성에 영향을 준다고 설명하고, 새 언어 문법을 설계할 때 고려할 원칙을 제안합니다.
- 주제
AI 요약
Lisp의 괄호 문법은 익숙하지 않아서 읽기 어렵다는 설명만으로 충분할까요? 이 글은 괄호의 배치와 코드의 모양이 사람의 시각 처리와 단기 기억에 어떤 부담을 주는지 살펴봅니다. 저자는 인지과학의 시각적 그룹화 원리를 문법 설계에 적용해, Lisp 표기가 C 계열 언어보다 어렵게 느껴지는 이유를 설명합니다.
시각적 그룹화와 괄호 배치
사람은 가까이 놓인 대상을 서로 관련 있는 묶음으로 인식하는 경향이 있습니다. 저자는 이를 Gestalt 심리학의 근접성 원리로 설명합니다. C 계열 함수 호출은 인수가 하나면 괄호와 이름이 붙어 보이고, 인수가 여러 개면 쉼표와 공백으로 인수 사이가 나뉩니다. 그 결과 흐릿하게 보더라도 코드의 대략적인 구조가 몇 개의 덩어리로 드러납니다. 반면 Lisp 표기에서는 함수와 인수를 모두 같은 공백으로 나누므로, 시각적으로 각 식별자가 따로 떨어져 보입니다.
괄호끼리의 거리도 차이를 만듭니다. C 계열 표기에서는 함수 이름이 여는 괄호 앞에 있어 여는 괄호와 닫는 괄호가 가까운 편입니다. Lisp에서는 여는 괄호 뒤에 함수 이름이 오므로 둘 사이가 멀어집니다. 저자는 시야 중심부만 선명하게 보인다는 점을 들어, 멀리 떨어진 괄호를 한눈에 짝짓기 어려워진다고 주장합니다. 조건문이나 반복문처럼 Lisp에서 여러 줄에 걸치는 식은 이 간격이 더 커질 수 있습니다. 닫는 괄호를 각 들여쓰기 수준에 맞춰 배치하면 괄호 수를 직접 세지 않고도 구조를 확인하기 쉬워집니다.
중첩과 읽는 순서
코드를 읽을 때는 아직 닫히지 않은 식의 문맥을 기억해야 합니다. 저자는 단기 기억이 한 번에 유지하는 항목이 대략 3~5개라고 설명하며, 중첩된 괄호를 기억하는 부담을 ‘정신적 스택’에 비유합니다. 일부 중첩은 표기에서 괄호를 반복하지 않고 연속 호출이나 배열 접근으로 나타낼 수 있습니다. 예를 들어 f(a)(b)처럼 이어 쓰면 왼쪽으로 중첩된 호출을 괄호 구조로 추적할 필요가 줄어듭니다.
또 다른 부담은 읽는 순서와 평가 순서가 어긋나는 경우입니다. 오른쪽으로 깊게 중첩된 식에서는 안쪽 식이 먼저 평가되지만, 글을 왼쪽에서 오른쪽으로 읽으면 바깥쪽 호출을 먼저 마주칩니다. 독자는 바깥 호출을 기억해 두거나 안쪽부터 거꾸로 읽어야 합니다. 저자는 함수형 코드를 선호하는 Lisp에서 이런 형태가 더 자주 나타날 수 있다고 설명합니다. 반면 명령형 코드는 실행 순서대로 단계를 적기 쉽고, 메서드 체이닝은 값이 전달되는 순서를 읽는 순서와 맞추는 경향이 있습니다. Clojure의 threading macro도 Lisp에서 읽는 순서를 정리하는 방식으로 제시합니다.
문법 설계에 관한 제안
저자는 중위 연산자나 if 같은 키워드의 유무가 가독성에 영향을 주기는 하지만, 논의에서 그 효과가 과장되는 경우가 많다고 봅니다. 편집기의 괄호 색상 표시도 짝을 찾는 데 도움을 주지만, Lisp와 C 계열 언어 모두에 적용되므로 분석의 초점에서는 제외합니다. 글에서 제시한 Lisp 가독성의 네 가지 원인은 접두 표기에서 괄호 사이가 멀어지는 점, 괄호 추적을 돕지 않는 서식 관행, 접두 표기에서 왼쪽 중첩이 늘어나는 점, 읽는 순서와 평가 순서를 맞추기 어렵다는 점입니다. 새 문법을 설계할 때는 관련 토큰을 가깝게 배치하고, 코드 형태로 묶음을 드러내며, 결합 방향을 활용해 불필요한 괄호 중첩을 줄이고, 읽는 순서와 평가 순서를 맞추라고 제안합니다.
Reddit 반응
- @u/Soupeeee — 제가 보기엔 Lisp 문법을 읽기 어렵게 하는 가장 큰 요인은 균일함입니다. 글에서 언급했듯 C에서는 동작마다 모양이 다릅니다. 대입문에는 시각적으로 끊어 주는 등호가 있고, 함수 호출은 글자들이 이어진 형태에 가깝습니다. 들여쓰기와 줄바꿈은 큰 도움이 되어 글에서 다룬 문제 일부를 줄입니다. 저는 실제로 Lisp의 중첩 함수 호출이 더 보기 좋다고 생각합니다.
- @u/particlemanwavegirl — 저도 형태가 없고 균질하다는 점과, 글에서 설명한 중첩 괄호의 정신적 스택을 유지해야 한다는 점이 함께 문제라고 봅니다.
- @u/wicked-canid — 들여쓰기만 보면 괄호는 대부분 잊어도 됩니다.
- @u/particlemanwavegirl — 모든 괄호가 각자 줄을 차지하지는 않습니다. 줄이 (( 또는 ( x (로 시작하는 경우가 흔합니다. 안쪽 닫는 괄호가 이 줄 안쪽에 있는지, 줄 끝에 있는지, 다음 블록 끝에 있는지, 현재 블록 끝에 있는지 읽을 때 여전히 판단해야 합니다. 서식도 제각각입니다. 제가 본 Lisp 코드 대부분은 닫는 괄호에 들여쓰기를 적용하지 않고 가장 안쪽 범위의 줄 끝에 몰아둡니다.
- @u/ScottBurson — 닫는 괄호 사이에 줄바꿈을 넣을 이유는 전혀 없습니다. 토큰과 닫는 괄호 사이를 줄바꿈하는 경우는 가끔 있지만, 저는 피하려고 합니다. s-expression 하나를 건너뛰는 편집기 명령과 현재 s-expression 끝으로 이동하는 명령만 있으면 됩니다. 편집기가 닫는 괄호가 이어진 곳에서 알맞은 위치를 찾아주므로 직접 세지 않아도 됩니다.
- @u/lxsameer — 저도 Lisp는 읽기 아주 쉽다고 생각합니다. 대부분의 방언은 규칙이 단순해서 작은 규칙 집합만 알아도 Lisp의 99% 정도를 이해할 수 있다는 점이 좋습니다. 다른 언어는 문법이 아주 복잡할 수 있습니다. 익숙해지는 데 시간은 조금 들지만, 전반적으로 이보다 단순한 언어는 없습니다.
- @u/Mickenfox — C에 ==와 {}가 있는 이유는 문법 수준에서 특별한 의미를 부여했기 때문입니다. 초기 함수형 언어의 장점은 모든 것을 언어 안의 함수로 낮추는 데 있었다고 이해합니다. 그래서 문법이 균질해졌습니다. 애초에 그게 나쁜 생각이었을 수도 있습니다.
- @u/Soupeeee — Lisp 문법이 그런 이유는 언어의 AST가 언어가 다루는 자료 구조이기도 하기 때문입니다. Lisp가 제공하는 도구로 Lisp 자료 구조를 해석하는 프로그램을 만들기 쉽습니다. 이를 homoiconicity라고 부릅니다. 원래는 재귀 연습에 가까웠지만, 람다 계산법과 연결된다는 점에서 계산 이론 관점에서도 흥미롭습니다.
- @u/Smalltalker-80 — 읽는 순서와 평가 순서를 최대한 같게 유지하면 가독성이 좋아집니다. 먼저 연산되는 값을 앞에 두고, 연산과 체이닝을 왼쪽에서 오른쪽으로 평가하는 방식입니다. 제 이름을 말해보세요.
- @u/Dusty_Coder — 그래서 extension method가 유행하는 겁니다.
- @u/L8_4_Dinner — 말은 아주 길지만 결론은 73년 된 Lisp가 여전히 대부분 사람에게 읽기 어렵다는 거군요.
- @u/reflexive-polytope — 저는 Lisp를 읽기 어렵다고 생각하지 않습니다. S-expression은 괜찮고 중괄호보다 나을 수도 있습니다. 하지만 문법은 그렇게 중요하지 않습니다. 문법은 알고리즘을 표현하는 매체일 뿐입니다. Lisp 코드를 이해하기 어려운 이유는 편재하는 동적 동작, 의미가 안정된 정의의 부족, 문법 외 언어 기능 대부분의 임의성입니다. 그래서 Lisp 코드를 읽는 일이 즐겁지 않습니다.
- @u/brat3108 — 두 시각화가 같은 데이터를 나타낸다고 볼 수 없습니다. 그래프에는 동일한 회색 사각형 98개와 이상치 두 개만 보이고 나머지 데이터는 사라졌습니다. 숫자에서도 이상치 외에는 전부 '-,-,-,-;'로 바꾸면 쉽게 찾을 수 있습니다. Lisp 가독성에 관해서는 문법이 너무 단조롭습니다. 변화가 거의 없습니다. 레이아웃과 들여쓰기가 도울 수 있는 데도 한계가 있습니다. 더 풍부한 문법에는 장점이 있습니다.
- @u/digikar — Lisp를 읽기 어렵다고 느끼는 분이라면 moonli-lang을 보세요.
- @u/digikar — 참고로 Lisp 사용자들은 괄호를 손으로 짝짓지 않습니다. 괄호 쌍을 삽입하고 괄호와 함께 코드를 조작합니다. 편집기가 괄호를 이용해 코드를 들여쓰게 하고, 그다음 들여쓰기를 보고 코드를 읽습니다.
- @u/Abrissbirne66 — 글 마지막에 언급한 괄호 색상 표시가 문제를 대부분 해결한다고 생각합니다. 문법이 올바르다고 이미 가정하면, 닫는 괄호가 줄 끝에 쌓여 있어도 들여쓴 형태가 큰 도움이 됩니다.
- @u/zhivago — Lisp가 읽기 어려운 이유는 Lisp가 아닌 언어가 읽기 어려운 이유와 같습니다. 익숙하지 않기 때문입니다.
원문: Paul T. McCarthy / 번역·요약: Trawling