SlideShare a Scribd company logo
동시성 프로그래밍하기 자바보다 좋은 Clojure
/ 김은민
왜 이런 주제를?
• 7가지 동시성 모델
이야기 할 내용
1. 동시에 값 하나를 바꾸는 좋은 방법 - Atom
2. 동시에 값 여럿을 바꾸는 좋은 방법 - Ref
3. 적은 리소스를 사용해서 동시 작업 간에 타이밍을 맞추는 방법 - core.async
Atom
1. 동시에 값 하나를 바꾸는 좋은 방법
스레드 안전하지 않은 Counter 코드
????????
스레드 안전하지 않은 Counter 코드
바이트 코드
읽고 - 바꾸고 - 쓰고
스레드 안전한 Counter 코드 ???
스레드 안전한 Counter 코드 ???
동기화 되지 않으면 메인 메모리에
쓰여지지 않고 CPU 캐시에 남은
값이 읽힐 수 있다.
스레드 안전한 Counter 코드
synchronized (Monitor)
• synchronized는 Tony Hoare가 고안한 Monitor라는 방식의 동기화 방법이다.
• 자바의 synchronized는 한번에 하나의 스레드가 접근 하기 위해 락을 사용한다.
락의 문제
• 스레드 경합이 없는 단일 스레드에서 락을 얻고 반납하는 일은 부하다.
• 락을 얻지 못하고 대기 해야하는 스레드가 많아지면 스레드 전환에 들어가는 비용
이 많아진다.
• 락은 다양한 활동성 문제(데드락, 라이브락, 소모)를 일으킬 수 있다.
자바 병렬 프로그래밍
‘병렬 알고리즘과 관련한 최근 연구 결과를 보면 대부분이 

넌블로킹 알고리즘, 즉 여러 스레드가 동작하는 환경에서 

데이터의 안정성을 보장하는 방법으로 락을 사용하는 

대신 저수준의 하드웨어에서 제공하는 

비교 후 교환 등의 명령을 사용하는 알고리즘을 다루고 있다.’
병렬 연산을 위한 하드웨어적인 지원
• 현대 프로세서는 CAS(Compare-and-swap) 연산을 제공한다.
• x86의 CMPXCHG instruction (ex. CMPXCHG r/m8,r8)
• CAS 연산은 값을 변경하기 위해 기존 값과 새 값을 하나의 명령어로 수행한다.
• 만약 기존 값이 변경 하려는 값과 같으면 새 값으로 바꾼다.
• CAS count, 1, 2 ( 기존 값이 1이면 2로 바꾼다. 그렇지 않으면 아무일도 하지
않는다.)
• 스레드 경쟁이 없다면 CAS 연산은 락을 사용하는 연산 보다 2배 빠르다. 

- 자바 병렬 프로그래밍 15장
• 자바는 java.util.Concurrent.atomic 패키지에 AtomicXxx 클래스에서 CAS연산
을 지원한다.
• C는 <stdatomic.h>에서 지원한다.
Atomic 클래스를 사용한 넌블로킹 Counter
newValue를 쓰려고 했는데
누군가 값을 바꿔 oldValue와 다르면 false!

그럼 다시 oldValue를 읽어서 시도한다.
락과 넌블로킹 성능 비교
1. 스래드 경쟁이 심한 경우
Lock > Atomic
2. 스래드 경쟁이 일반 적인 경우
Lock < Atomic
클로저 스레드
클로저의 atom을 이용한 넌블로킹 Counter
클로저의 atom을 이용한 넌블로킹 Counter
클로저의 atom을 이용한 넌블로킹 Counter
Ref
2. 동시에 값 여럿을 바꾸는 좋은 방법
자바 병렬 프로그래밍
‘병렬 알고리즘과 관련한 최근 연구 결과를 보면 대부분이 

넌블로킹 알고리즘, 즉 여러 스레드가 동작하는 환경에서 

데이터의 안정성을 보장하는 방법으로 

락을 사용하는 대신 …’
MVCC (Multiversion connurrency control)
• Multiversion concurrency control (MCC or MVCC), is a concurrency control
method commonly used by database management systems to provide
concurrent access to the database and in programming languages to
implement transactional memory.

…

MVCC provides point in time consistent views. Read transactions under
MVCC typically use a timestamp or transaction ID to determine what state
of the DB to read, and read these versions of the data. Read and write
transactions are thus isolated from each other without any need for
locking. Writes create a newer version, while concurrent reads access the
older version.
• 구현이 힘들어 자바 예제는 생략합니다. ㅜㅠ
• 클로저 Ref는 STM을 이용한 MVCC 방식의 트랜잭션 기능
• 예제
• checking 계좌에 1만원
• savings 계좌에 2만원
• checking 계좌에서 savings 계좌로 100원씩 100번 1만원 보낸다.
• savings 계좌에서 checking 계좌로 200원씩 100번 2만원 보낸다.
• 결국 savings 계좌에서 checking 계좌로 1만원 보낸다.
클로저 Ref 예제
클로저 Ref 예제
클로저 Ref 예제
200번이 아니다!
299번은 재시도 되었다.
core.async
3. 적은 리소스를 사용해서 동시 작업 간에 

타이밍을 맞추는 방법
Latch를 이용한 스레드 동기화
• java.util.concurrent 패키지에 Latch 지원 클래스가 있다.
• 예제
• Worker1은 1초에 한번씩 10회 화면에 횟수를 출력한다.
• Worker2는 기다렸다가 Worker1이 5회가 되면 1초에 한번씩 10회 화면에 횟
수를 출력한다.
• Worker1과 Worker2는 동시에 시작하지만 Worker2는 Worker1이 5회가 될
때까지 기다려야 한다.
Latch를 이용한 스레드 동기화 예제 - Worker1
Latch를 이용한 스레드 동기화 예제 - Worker2
latch가 0이 될때 까지 블로킹
Latch를 이용한 스레드 동기화 예제
Future를 이용한 스레드 동기화
• java.util.concurrent 패키지에 Future 관련 클래스가 있다.
• 예제
• Worker1은 0부터 9까지 합을 구한다.
• Worker2는 기다렸다가 Worker1의 결과에 0부터 9까지 합을 더한다.
• Worker1과 Worker2는 동시에 시작하지만 Worker2는 Worker1이 결과를 줄
때까지 기다린다.
Future를 이용한 스레드 동기화 - Worker1
Future를 이용한 스레드 동기화 - Worker2
Worker1 작업이 끝나고
결과가 나올 때 까지 블로킹
Future를 이용한 스레드 동기화
클로저 future
@는 Future.get이므로 future가 종료될 때까지 블로킹
클로저 future
클로저 future와 promise
프로그램이 끝나지 않도록 블로킹하며 

future가 끝나기를 기다린다.
자바 병렬 프로그래밍
‘병렬 알고리즘과 관련한 최근 연구 결과를 보면 대부분이 

넌블로킹 알고리즘, 즉 여러 스레드가 동작하는 환경에서 

데이터의 안정성을 보장하는 방법으로 …’
다시 넌블로킹
• future와 promise는 작업을 블로킹 하면서 타이밍을 맞춘다.
• 스레드가 많이 블로킹되면 대기하는 스레드가 많아져 리소스가 낭비된다.
• 블로킹 대신 스레드를 종료하고 이벤트를 기다렸다 다시 스레드를 실행하는 

이벤트 방식은 효율적이다.
자바 이벤트 기반 예제
onCreate 스레드는 종료된다.
클릭 이벤트가 발생하면 다음 로직을 실행한다.
하지만 콜백 헬…
core.async
• 클로저 CSP(Communicating sequential processes - Tony Hoare 1977) 

라이브러리
• 채널 기반의 동시성 흐름 제어 패턴
• Go 언어에서 기본 동시성 기능으로 제공
core.async
• 채널
체널에 값이 들어올 때 까지 블로킹
체널에 값을 쓴다
core.async
• 신비스러운 Go 루틴 스레드 풀에서 가져온 스레드에서
채널에 값이 들어오길 기다리는 

이벤트 핸들러를 만들고 스레드 종료
채널에 값이 들어오면
스레드 풀에서 스레드를 가져와
x에 값을 설정하고
다시 채널에 값이 들어오길 기다리는
이벤트 핸들러를 만들고 스레드 종료채널에 값이 들어오면
스레드를 풀에서 가져와서
y에 값을 설정하고 x와 y를
더한 값을 출력하고 스레드 종료
core.async
• 논블록킹 방식으로 주어진 웹 페이지의 단어 수 세기
넌블로킹과 순차흐름의 장점을 모두 가질 수 있다.
대기하는 동안 스레드를 점유하지 않기 때문에 적은 리소스를
사용하는 효율적인 코드를 작성할 수 있다.
아쉽지만 능력 부족으로 다루지 못한 내용
• 함수형 프로그래밍과 동시성
• pmap, reducer, transducer … & Rx
• Functional Reactive Programing
• CSP
결론으로 가는 중
• 저수준 언어에서 제공하는 스레드와 락 같은 기본 동시성 기능은 

요즘 같은 멀티 코어 환경에서 많은 노력을 해야 재대로 코드를 작성할 수 있다.
• java.concurrent 패키지 처럼 동시성 관련 라이브러리를 사용하는 것이 좋다.
• 하지만 언어의 기본 기능으로 제공되는 편리한 스레드와 락의 유혹에서 벗어나기
어렵다.
• 현대 프로그래밍 언어들을 기본 언어 기능으로 훌륭한 동시성 기능을 제공한다.
진짜 결론
• 1958년에 고안된 Lisp(클로저)은 저수준 언어인가?
• 라이브러리를 사용하는 것보다 언어에서 제공해야 하는 것이 아닌가?
• Lisp의 s-expression은 시대를 초월한다.
Thanks
(quantum-process …

More Related Content

PPTX
1.1 review on algebra 1
PPT
2.7 Piecewise Functions
PPTX
Statistical and Non-Statistical Question.pptx
PDF
PPTX
Mathematical Induction
PDF
3.9.1 Dilation, Scale Factor, and Proportion
PPTX
Limits of functions
PPT
Solving Systems of Linear Inequalities
1.1 review on algebra 1
2.7 Piecewise Functions
Statistical and Non-Statistical Question.pptx
Mathematical Induction
3.9.1 Dilation, Scale Factor, and Proportion
Limits of functions
Solving Systems of Linear Inequalities

What's hot (20)

PPT
Piecewise function lesson 3
PPTX
1.6 slopes and the difference quotient
DOCX
Binomial theorem
PPTX
5.1 anti derivatives
PDF
4.1 Inverse Functions
PPT
Parent Functions
PPTX
5.4 mathematical induction
PPTX
Relations & Functions
PPTX
Index laws ppt
PDF
Lesson 9: The Product and Quotient Rules (slides)
PPT
LOGARITHMIC AND EXPONENTIAL FUNCTIONS.ppt
PPTX
Relation and function pdf
PPTX
Quadratic function
PPTX
System of linear inequalities
PPTX
Graph of a linear function
PDF
ΠΛΗ20 ΤΥΠΟΛΟΓΙΟ ΣΥΝΔΥΑΣΤΙΚΗΣ
PPS
Solving Linear Equations
PPT
Rate of change and tangent lines
PDF
Lesson 27: Integration by Substitution (slides)
PPSX
Exponential & Logarithmic Functions--.ppsx
Piecewise function lesson 3
1.6 slopes and the difference quotient
Binomial theorem
5.1 anti derivatives
4.1 Inverse Functions
Parent Functions
5.4 mathematical induction
Relations & Functions
Index laws ppt
Lesson 9: The Product and Quotient Rules (slides)
LOGARITHMIC AND EXPONENTIAL FUNCTIONS.ppt
Relation and function pdf
Quadratic function
System of linear inequalities
Graph of a linear function
ΠΛΗ20 ΤΥΠΟΛΟΓΙΟ ΣΥΝΔΥΑΣΤΙΚΗΣ
Solving Linear Equations
Rate of change and tangent lines
Lesson 27: Integration by Substitution (slides)
Exponential & Logarithmic Functions--.ppsx
Ad

Viewers also liked (8)

PDF
Clojure Monad
PDF
Clojure HTTP API 서버 구현을 위한 라이브러리
PDF
core.logic (Clojure)
PDF
제 5회 Lisp 세미나 - 클로저 개발팀을 위한 지속적인 통합
PDF
제 5회 Lisp 세미나 - Graphics Programming in Clojure
PDF
Re frame
PDF
Dragon: A Distributed Object Storage at Yahoo! JAPAN (WebDB Forum 2017 / E...
PDF
Dragon: A Distributed Object Storage at Yahoo! JAPAN (WebDB Forum 2017)
Clojure Monad
Clojure HTTP API 서버 구현을 위한 라이브러리
core.logic (Clojure)
제 5회 Lisp 세미나 - 클로저 개발팀을 위한 지속적인 통합
제 5회 Lisp 세미나 - Graphics Programming in Clojure
Re frame
Dragon: A Distributed Object Storage at Yahoo! JAPAN (WebDB Forum 2017 / E...
Dragon: A Distributed Object Storage at Yahoo! JAPAN (WebDB Forum 2017)
Ad

Similar to 동시성 프로그래밍 하기 좋은 Clojure (20)

PPTX
7가지 동시성 모델 - 6장. 순차 프로세스 통신
PDF
자바 병렬 프로그래밍 1&2
PDF
R2서버정진욱
PPTX
4-1. javascript
PPTX
More effective c++ 2
PPTX
0.javascript기본(~3일차내)
PDF
실시간 게임 서버 최적화 전략
PPTX
Mec++ chapter3,4
PPTX
Concurrent programming
PDF
제프리 리처의 Windows via C/C++ : 8장 유저 모드에서의 스레드 동기화
PPTX
Dropbox와 같은 시스템은 파일을 어떻게 저장할까?
PDF
Asynchronous 101 - (1)
PPT
스타트업과 개발자를 위한 AWS 클라우드 태권 세미나 : VCNC 사례 발표
PPTX
AWS lambda, step function, cloud watch
PPT
자바와 사용하기2
PPTX
golang과 websocket을 활용한 서버프로그래밍 - 장애없는 서버 런칭 도전기
PDF
엘라스틱서치 클러스터로 수십억 건의 데이터 운영하기
PPTX
Windows via C/C++ 06 스레드의 기본
PDF
Microsoft pp lpdf
PDF
Anatomy of Realm
7가지 동시성 모델 - 6장. 순차 프로세스 통신
자바 병렬 프로그래밍 1&2
R2서버정진욱
4-1. javascript
More effective c++ 2
0.javascript기본(~3일차내)
실시간 게임 서버 최적화 전략
Mec++ chapter3,4
Concurrent programming
제프리 리처의 Windows via C/C++ : 8장 유저 모드에서의 스레드 동기화
Dropbox와 같은 시스템은 파일을 어떻게 저장할까?
Asynchronous 101 - (1)
스타트업과 개발자를 위한 AWS 클라우드 태권 세미나 : VCNC 사례 발표
AWS lambda, step function, cloud watch
자바와 사용하기2
golang과 websocket을 활용한 서버프로그래밍 - 장애없는 서버 런칭 도전기
엘라스틱서치 클러스터로 수십억 건의 데이터 운영하기
Windows via C/C++ 06 스레드의 기본
Microsoft pp lpdf
Anatomy of Realm

동시성 프로그래밍 하기 좋은 Clojure

  • 1. 동시성 프로그래밍하기 자바보다 좋은 Clojure / 김은민
  • 2. 왜 이런 주제를? • 7가지 동시성 모델
  • 3. 이야기 할 내용 1. 동시에 값 하나를 바꾸는 좋은 방법 - Atom 2. 동시에 값 여럿을 바꾸는 좋은 방법 - Ref 3. 적은 리소스를 사용해서 동시 작업 간에 타이밍을 맞추는 방법 - core.async
  • 4. Atom 1. 동시에 값 하나를 바꾸는 좋은 방법
  • 5. 스레드 안전하지 않은 Counter 코드 ????????
  • 6. 스레드 안전하지 않은 Counter 코드 바이트 코드 읽고 - 바꾸고 - 쓰고
  • 8. 스레드 안전한 Counter 코드 ??? 동기화 되지 않으면 메인 메모리에 쓰여지지 않고 CPU 캐시에 남은 값이 읽힐 수 있다.
  • 10. synchronized (Monitor) • synchronized는 Tony Hoare가 고안한 Monitor라는 방식의 동기화 방법이다. • 자바의 synchronized는 한번에 하나의 스레드가 접근 하기 위해 락을 사용한다.
  • 11. 락의 문제 • 스레드 경합이 없는 단일 스레드에서 락을 얻고 반납하는 일은 부하다. • 락을 얻지 못하고 대기 해야하는 스레드가 많아지면 스레드 전환에 들어가는 비용 이 많아진다. • 락은 다양한 활동성 문제(데드락, 라이브락, 소모)를 일으킬 수 있다.
  • 12. 자바 병렬 프로그래밍 ‘병렬 알고리즘과 관련한 최근 연구 결과를 보면 대부분이 
 넌블로킹 알고리즘, 즉 여러 스레드가 동작하는 환경에서 
 데이터의 안정성을 보장하는 방법으로 락을 사용하는 
 대신 저수준의 하드웨어에서 제공하는 
 비교 후 교환 등의 명령을 사용하는 알고리즘을 다루고 있다.’
  • 13. 병렬 연산을 위한 하드웨어적인 지원 • 현대 프로세서는 CAS(Compare-and-swap) 연산을 제공한다. • x86의 CMPXCHG instruction (ex. CMPXCHG r/m8,r8) • CAS 연산은 값을 변경하기 위해 기존 값과 새 값을 하나의 명령어로 수행한다. • 만약 기존 값이 변경 하려는 값과 같으면 새 값으로 바꾼다. • CAS count, 1, 2 ( 기존 값이 1이면 2로 바꾼다. 그렇지 않으면 아무일도 하지 않는다.) • 스레드 경쟁이 없다면 CAS 연산은 락을 사용하는 연산 보다 2배 빠르다. 
 - 자바 병렬 프로그래밍 15장 • 자바는 java.util.Concurrent.atomic 패키지에 AtomicXxx 클래스에서 CAS연산 을 지원한다. • C는 <stdatomic.h>에서 지원한다.
  • 14. Atomic 클래스를 사용한 넌블로킹 Counter newValue를 쓰려고 했는데 누군가 값을 바꿔 oldValue와 다르면 false!
 그럼 다시 oldValue를 읽어서 시도한다.
  • 15. 락과 넌블로킹 성능 비교 1. 스래드 경쟁이 심한 경우 Lock > Atomic 2. 스래드 경쟁이 일반 적인 경우 Lock < Atomic
  • 17. 클로저의 atom을 이용한 넌블로킹 Counter
  • 18. 클로저의 atom을 이용한 넌블로킹 Counter
  • 19. 클로저의 atom을 이용한 넌블로킹 Counter
  • 20. Ref 2. 동시에 값 여럿을 바꾸는 좋은 방법
  • 21. 자바 병렬 프로그래밍 ‘병렬 알고리즘과 관련한 최근 연구 결과를 보면 대부분이 
 넌블로킹 알고리즘, 즉 여러 스레드가 동작하는 환경에서 
 데이터의 안정성을 보장하는 방법으로 
 락을 사용하는 대신 …’
  • 22. MVCC (Multiversion connurrency control) • Multiversion concurrency control (MCC or MVCC), is a concurrency control method commonly used by database management systems to provide concurrent access to the database and in programming languages to implement transactional memory.
 …
 MVCC provides point in time consistent views. Read transactions under MVCC typically use a timestamp or transaction ID to determine what state of the DB to read, and read these versions of the data. Read and write transactions are thus isolated from each other without any need for locking. Writes create a newer version, while concurrent reads access the older version. • 구현이 힘들어 자바 예제는 생략합니다. ㅜㅠ
  • 23. • 클로저 Ref는 STM을 이용한 MVCC 방식의 트랜잭션 기능 • 예제 • checking 계좌에 1만원 • savings 계좌에 2만원 • checking 계좌에서 savings 계좌로 100원씩 100번 1만원 보낸다. • savings 계좌에서 checking 계좌로 200원씩 100번 2만원 보낸다. • 결국 savings 계좌에서 checking 계좌로 1만원 보낸다. 클로저 Ref 예제
  • 25. 클로저 Ref 예제 200번이 아니다! 299번은 재시도 되었다.
  • 26. core.async 3. 적은 리소스를 사용해서 동시 작업 간에 
 타이밍을 맞추는 방법
  • 27. Latch를 이용한 스레드 동기화 • java.util.concurrent 패키지에 Latch 지원 클래스가 있다. • 예제 • Worker1은 1초에 한번씩 10회 화면에 횟수를 출력한다. • Worker2는 기다렸다가 Worker1이 5회가 되면 1초에 한번씩 10회 화면에 횟 수를 출력한다. • Worker1과 Worker2는 동시에 시작하지만 Worker2는 Worker1이 5회가 될 때까지 기다려야 한다.
  • 28. Latch를 이용한 스레드 동기화 예제 - Worker1
  • 29. Latch를 이용한 스레드 동기화 예제 - Worker2 latch가 0이 될때 까지 블로킹
  • 30. Latch를 이용한 스레드 동기화 예제
  • 31. Future를 이용한 스레드 동기화 • java.util.concurrent 패키지에 Future 관련 클래스가 있다. • 예제 • Worker1은 0부터 9까지 합을 구한다. • Worker2는 기다렸다가 Worker1의 결과에 0부터 9까지 합을 더한다. • Worker1과 Worker2는 동시에 시작하지만 Worker2는 Worker1이 결과를 줄 때까지 기다린다.
  • 32. Future를 이용한 스레드 동기화 - Worker1
  • 33. Future를 이용한 스레드 동기화 - Worker2 Worker1 작업이 끝나고 결과가 나올 때 까지 블로킹
  • 35. 클로저 future @는 Future.get이므로 future가 종료될 때까지 블로킹
  • 37. 클로저 future와 promise 프로그램이 끝나지 않도록 블로킹하며 
 future가 끝나기를 기다린다.
  • 38. 자바 병렬 프로그래밍 ‘병렬 알고리즘과 관련한 최근 연구 결과를 보면 대부분이 
 넌블로킹 알고리즘, 즉 여러 스레드가 동작하는 환경에서 
 데이터의 안정성을 보장하는 방법으로 …’
  • 39. 다시 넌블로킹 • future와 promise는 작업을 블로킹 하면서 타이밍을 맞춘다. • 스레드가 많이 블로킹되면 대기하는 스레드가 많아져 리소스가 낭비된다. • 블로킹 대신 스레드를 종료하고 이벤트를 기다렸다 다시 스레드를 실행하는 
 이벤트 방식은 효율적이다.
  • 40. 자바 이벤트 기반 예제 onCreate 스레드는 종료된다. 클릭 이벤트가 발생하면 다음 로직을 실행한다.
  • 42. core.async • 클로저 CSP(Communicating sequential processes - Tony Hoare 1977) 
 라이브러리 • 채널 기반의 동시성 흐름 제어 패턴 • Go 언어에서 기본 동시성 기능으로 제공
  • 43. core.async • 채널 체널에 값이 들어올 때 까지 블로킹 체널에 값을 쓴다
  • 44. core.async • 신비스러운 Go 루틴 스레드 풀에서 가져온 스레드에서 채널에 값이 들어오길 기다리는 
 이벤트 핸들러를 만들고 스레드 종료 채널에 값이 들어오면 스레드 풀에서 스레드를 가져와 x에 값을 설정하고 다시 채널에 값이 들어오길 기다리는 이벤트 핸들러를 만들고 스레드 종료채널에 값이 들어오면 스레드를 풀에서 가져와서 y에 값을 설정하고 x와 y를 더한 값을 출력하고 스레드 종료
  • 45. core.async • 논블록킹 방식으로 주어진 웹 페이지의 단어 수 세기 넌블로킹과 순차흐름의 장점을 모두 가질 수 있다. 대기하는 동안 스레드를 점유하지 않기 때문에 적은 리소스를 사용하는 효율적인 코드를 작성할 수 있다.
  • 46. 아쉽지만 능력 부족으로 다루지 못한 내용 • 함수형 프로그래밍과 동시성 • pmap, reducer, transducer … & Rx • Functional Reactive Programing • CSP
  • 47. 결론으로 가는 중 • 저수준 언어에서 제공하는 스레드와 락 같은 기본 동시성 기능은 
 요즘 같은 멀티 코어 환경에서 많은 노력을 해야 재대로 코드를 작성할 수 있다. • java.concurrent 패키지 처럼 동시성 관련 라이브러리를 사용하는 것이 좋다. • 하지만 언어의 기본 기능으로 제공되는 편리한 스레드와 락의 유혹에서 벗어나기 어렵다. • 현대 프로그래밍 언어들을 기본 언어 기능으로 훌륭한 동시성 기능을 제공한다.
  • 48. 진짜 결론 • 1958년에 고안된 Lisp(클로저)은 저수준 언어인가? • 라이브러리를 사용하는 것보다 언어에서 제공해야 하는 것이 아닌가? • Lisp의 s-expression은 시대를 초월한다.