mir.pe (일반/어두운 화면)
최근 수정 시각 : 2024-10-11 21:28:30

LISP

Lisp에서 넘어옴

파일:나무위키+유도.png  
은(는) 여기로 연결됩니다.
다른 뜻에 대한 내용은 LISP(동음이의어) 문서
번 문단을
부분을
, 에 대한 내용은 문서
번 문단을
번 문단을
부분을
부분을
, 에 대한 내용은 문서
번 문단을
번 문단을
부분을
부분을
, 에 대한 내용은 문서
번 문단을
번 문단을
부분을
부분을
, 에 대한 내용은 문서
번 문단을
번 문단을
부분을
부분을
, 에 대한 내용은 문서
번 문단을
번 문단을
부분을
부분을
, 에 대한 내용은 문서
번 문단을
번 문단을
부분을
부분을
, 에 대한 내용은 문서
번 문단을
번 문단을
부분을
부분을
, 에 대한 내용은 문서
번 문단을
번 문단을
부분을
부분을
, 에 대한 내용은 문서
번 문단을
번 문단을
부분을
부분을
참고하십시오.
프로그래밍 사이트 선정 프로그래밍 언어 순위 목록
{{{#!wiki style="margin: 0 -10px -5px; word-break: keep-all"
{{{#!wiki style="display: inline-table; min-width: 25%; min-height: 2em;"
{{{#!folding [ IEEE Spectrum 2024 ]
{{{#!wiki style="margin: -5px 0"
<rowcolor=#fff> 스펙트럼 부문 상위 10개 프로그래밍 언어 직업 부문 상위 10개 프로그래밍 언어
1 Python 1 SQL
2 Java 2 Python
3 JavaScript 3 Java
4 C++ 4 TypeScript
5 TypeScript 5 SAS
6 SQL 6 JavaScript
7 C# 7 C#
8 Go 8 HTML
9 C 9 Shell
10 HTML 10 C++
}}}
}}}
}}}
[ Stack Overflow 2024 ]
[ TIOBE 2024 ]
||<tablewidth=100%><width=9999><-4><bgcolor=deepskyblue><tablebgcolor=#fff,#222> 2024년 8월 기준 검색어 점유율 상위 20개 프로그래밍 언어 ||
1 Python 11 MATLAB
2 C++ 12 Delphi / Object Pascal
3 C 13 PHP
4 Java 14 Rust
5 C# 15 Ruby
6 JavaScript 16 Swift
7 SQL 17 Assembly language
8 Visual Basic 18 Kotlin
9 Go 19 R
10 Fortran 20 Scratch
{{{#!wiki style="margin: 0 -10px -5px; min-height: calc(1.5em + 5px);"
{{{#!folding [ 21위 ~ 50위 펼치기 · 접기 ]
{{{#!wiki style="margin: -5px -1px -11px"
21 COBOL 36 Scala
22 Classic Visual Basic 37 Transact-SQL
23 LISP 38 PL/SQL
24 Prolog 39 ABAP
25 Perl 40 Solidity
26 (Visual) FoxPro 41 GAMS
27 SAS 42 PowerShell
28 Haskell 43 TypeScript
29 Dart 44 Logo
30 Ada 45 Wolfram
31 D 46 Awk
32 Julia 47 RPG
33 Objective-C 48 ML
34 VBScript 49 Bash
35 Lua 50 Elixir
}}}}}}}}} ||
[ PYPL 2024 ]

}}} ||
프로그래밍 언어 목록 · 분류 · 문법

(format t "Hello, World!")
리스프
LISP
파일:LISP_logo.svg 파일:LISP_logo.svg
개발자 존 매카시
최초 공개 1958년 ([age(1958-01-01)]년 전)

1. 개요2. 역사3. 다른 프로그래밍 언어에 미친 영향4. 특징
4.1. Atom4.2. 리스트4.3. 문법4.4. Code is data, data is code4.5. 람다 함수4.6. 매크로4.7. Lisp-1, Lisp-2
5. SICP와 리스프에 대한 오해6. 리스프 사투리7. 커먼 리스프와 스킴 차이8. 여담9. 관련 문서10. 외부 링크

[clearfix]

1. 개요

파일:external/imgs.xkcd.com/lisp_cycles.png
"LISP은 반 세기가 넘었는데도 여전히 변치 않는 완벽함이 느껴져."
"이 싸이클이 영원히 계속될지 궁금하네. 새로운 세대의 코더들 중 몇 명이 매번 LISP을 재발견하는거지."
" 네 아버지의 괄호들이란다. 더 고상한 시대에 걸맞은 우아한 무기들이지."
xkcd 297화
리스프는 언어가 아니라 건축 자재이다.
Lisp isn’t a language, it’s a building material.
앨런 케이

LISt Processor Lots of Irritating Superfluous Parentheses

리스프(LISP)는 프로그래밍 언어의 한 종류로 대표적인 함수형 언어이다.

프로그래밍 언어의 역사를 말할 때, 현대의 컴퓨터를 위해 등장한 고급 언어 중 가장 오래된 것이 포트란이고, 두 번째로 오래된 것이 바로 이 리스프다. 역사가 긴 만큼 소위 Lisp-family라 불리는 여러 가지 사투리가 존재하고 이것들이 너무 다양하게 난립했기 때문에 공통 표준 규격을 만들어 1984년에 커먼 리스프(Common Lisp)가 탄생했다. 보통 리스프라고 말하면 이러한 사투리까지 모두 포함하는 의미로 사용된다. 최초 표기는 LISP이었지만 어느새 Lisp으로 표기되기 시작했으며, 지금은 Lisp이 널리 쓰인다.

2. 역사

1958년 미국 MIT의 존 매카시가 개발했는데, 당시 매카시는 인공지능을 연구하는 프로젝트에서 FORTRAN에서 목록 작업을 수행하는 서브루틴의 패키지로 Fortran List Processing Language(FLPL)을 구현한다. 이것이 리스프의 모태가 되어 1958년에 리스프가 세상에 등장하게 된다. 이후 상당기간 리스프는 인공지능 관련 언어라는 인식이 강했는데 이맥스(Emacs), AutoCAD 등 인공지능과 전혀 관련없는 분야에서도 리스프가 사용되면서 이러한 인식이 많이 옅어졌다.

3. 다른 프로그래밍 언어에 미친 영향

언어 자체가 새로운 기능을 탑재하기 걸맞게 유연하기도 하고, 오랫동안 학계의 특정 분야에서 거의 표준적으로 사용된 언어였기 때문에 리스프가 후대 언어에 끼친 영향은 매우 크다. if-then-else 형식, 재귀함수, 쓰레기 수집, JIT, 동적 타이핑, 동적 메모리 할당, 일급 함수 객체, 액터 모델 등 명령형이고 함수형이고를 불문하고 간접적인 영향까지 포함하면 프로그래밍 언어 중 리스프의 영향을 받지 않은 것을 찾아보기 힘들 정도이다.

4. 특징

4.1. Atom

초기 리스프의 데이터형은 Atom과 리스트로 구분되었다. Atom은 상수나 심볼을 뜻하고 리스트는 이러한 Atom 또는 다른 리스트를 원소로 포함하며 유한한 길이를 가진다. 여기서 두드러지는 특징은, Atom의 값이 불변(immutable)이라는 점이다.

이후 여러 리습 사투리가 개발되고 분화되는 과정에서 Atom의 불변 특성이 사라지는 경우도 많이 발생했으며 이는 아마도 실용적인 목적에 의해 이렇게 된 것이 아닐까라고 추측한다.

4.2. 리스트

리스프에는 기본적으로 개수를 셀 수 있고 변경 가능한 리스트가 기본 자료형으로 주어진다. 리스트는 그 자체로 Atom과 함께 다른 리스트의 원소가 될 수 있다.

여담으로 자료구조를 리스프 방언으로 진행하게 되면 코딩 분량이 팍팍 줄어드는 신세계를 맛볼 수 있는데 이는 리스프가 기본적으로 리스트 자료형을 제공하기 때문인 것도 한몫 한다.( Python으로 해도 유사한 경험을 할 수 있다.)

4.3. 문법

(+ 1 (if t 2 3)) ;=> 3
}}}t 는 리스프에서 참값을 나타내는 값이다.(타언어에서 True 또는 true와 같다.) (sort '(3 2 1) #'<) ;=> (1 2 3)
(mapcar #'(lambda (x) (1+ x)) '(1 2 3)) ;=> (2 3 4)
}}} 1 + 2
}}} (+ 1 2)
}}}

4.4. Code is data, data is code

데이터와 코드를 저장할 때 같은 자료 구조를 사용하는 프로그래밍 언어를 homoiconic하다고 한다.

리스프는 처음부터 후대에 등장하는 다른 프로그래밍 언어와 여러 가지 면에서 달랐다. 가장 큰 특징으로는 코드가 마치 데이터처럼 취급된다는 것이었는데 이는 데이터와 코드가 모두 리스트 형태로 표기되었기 때문이다. 이 리스트는 리스프에서 가장 중요한 요소로 볼 수 있는데 쉽게 말해 자료를 순서를 매겨 저장하는 것이라고 생각할 수 있다. 예를 들어 (+ 1 2)라는 리스트를 입력하면 코드로 해석이 되어(평가, Evaluation) + 함수에 1과 2를 인자로 넘겨주고, 1 + 2가 연산되어 3을 출력하며, 평가하지 말고 그대로 리스트로 저장하는 '를 붙여서 '(+ 1 2)를 입력하면 첫 번째 원소가 +이고 두 번째 원소가 1, 세 번째 원소가 2인 리스트로 인식된다. 저 리스트를 코드로 보고 그대로 실행할 수도 있고, 실행하지 않고 다른 함수에 리스트형 데이터로 넘겨주는 것도 가능하다는 소리이다.
#!syntax lisp
(f)  ; f라는 함수를 실행한다.
'(f) ; f라는 값이 담긴 리스트를 만든다.

코드를 데이터로 취급할 수 있다는 장점에 힘입어 셸 언어(scsh 같은), 문서 편집기(대표적으로 Emacs), 설계 시스템(CAD) 같은 소프트웨어의 기능을 늘리는 언어로 사용되거나 인공지능 분야에 많이 사용된다. 그 밖에 자연어 처리, 해석학, 게임 이론 같은 여러 분야에서 광범위하게 사용되고 있다.

리스프가 아닌 언어 중에도 물론 이런 특성을 가진 언어는 존재한다. io 같은 언어가 이러한 특성을 가지고 있다.[1] 하지만 아무도 안 쓰고 있다. Julia 언어도 이 특성을 가지고 있다.

4.5. 람다 함수

사실 리스프는 람다 계산법 프로그래밍 언어 형태로 구현한 것에 여러 가지 다른 기능을 추가한 것에 지나지 않는다고 할 수 있다. 따라서 소위 익명 함수를 뜻하는 Lambda Function도 정의하여 사용할 수 있다. 이 자체만으로는 "표현 가능"하다는 것 외에 의미가 없지만 리스프 계통 언어에서 주어지는 기본 함수나 API가 이를 적극 사용하여 코딩 노가다를 줄이면서 동시에 편리하게 코딩을 할 수 있도록 도와주는 강력한 요소이다.

예를 들어 Java 7 이하의 API에서 지원하는 컬렉션 정렬 기능을 사용하려면 Comparator 인터페이스를 구현하여 compare 메서드를 구현해야 한다. 고작 이거 하나 하려고 클래스를 하나 더 만들어야 한다. 하지만 리스프에서는 그냥 람다 함수로 대소 비교를 할 수 있는 익명 함수를 정의해서 파라미터로 넘기면 끝이다. 이러한 편의성 덕분에 .NET에서는 진작에 Framework 3.5 버전부터 람다식을 지원하고 있고, Java 역시 8부터 람다식을 수용하여 보다 편리하게 코딩할 수 있게 되었다.

4.6. 매크로

리스프의 돋보이는 특징 중 하나로 매크로가 있다. 이것을 사용하면 원하는 바에 따라 함수형으로도, 절차형으로도, 객체 지향형으로도, 논리형으로도 사용이 가능하다. 사용 가능한 프로그래머들의 우월감이 쩔기로 유명하다.

이 기능은 매우 쉽게 말해서 C 언어#define과 유사하지만 훨씬 강력한 기능을 제공한다. C의 #define은 소스 코드의 전처리기에 의해 미리 정의된 내용을 소스 코드 수준에서 치환하는 데 그치지만, 리스프의 매크로는 모든 것을 리스트에 들어있는 내용으로 치환하는 덕에, 실행 도중에 미리 정의된 프로그램으로 직접 치환된다. 즉, 매크로 자체가 입력되는 리스트의 내용을 미리 정의된 리스트의 내용으로 대체하는 함수이다.

리스프의 특성과 맞물린 이 기능이 너무나 강력하기 때문에, 리스프는 (자기 자신을) 프로그래밍 할 수 있는 프로그래밍 언어(Programmable programming language[2])라고도 불리며, 매크로를 사용하면 프로그래머가 리스프 내에서 새로운 문법을 정의하며 사용하는 것이 가능할 정도로 강력하다. 따라서 새로운 패러다임이 나타나도 리스프 내에서 그 기능을 매크로를 사용하여 구현 후, 동일한 리스프 언어로, 동일한 컴파일러를 사용하며 프로그램을 작성하는 것이 얼마든지 가능하다.[3] 리스프로 만들어진 프로그램들도 이런 특징을 이어받는 경우가 많은데, 리스프의 이런 특징을 한계까지 끌어낸 이맥스도 자체 기능을 거의 전부 커스터마이징이 가능하며 에디터가 아니라 그냥 거대한 리스프 인터프리터라는 평가를 받는다.(...)

하지만 기능이 강력한 만큼 양날의 검 같은 존재가 바로 이 매크로이다. 나 혼자서만 작업하는 경우면 상관없으나 여러 사람이 작성하는 프로그램에서 사전에 충분한 협의 없이 만들어 쓰는 매크로는 프로그램 전체에 독이 될 가능성이 높다. 먼저 다른 개발자가 설명을 듣거나 해당 매크로의 소스코드를 완전히 이해하기 전에는 코드를 해독하거나 사용하기 힘들고, 여러 명이 공동 작업으로 프로그램을 작성한다는 자체가 프로그램의 덩치가 꽤 크다는 것을 뜻하기 때문에 충분한 사전검토나 협의 없이 만들어진 매크로는 안 만드니 못하는 경우도 충분히 있을 수 있기 때문이다.

그리고 성능상의 문제나 기타 다른 이유 때문에 매크로가 없는 구현체도 꽤 많이 존재한다.

4.7. Lisp-1, Lisp-2

}}} }}} }}} user=> (def a 4)
#'user/a
;; 아랫줄에서 심볼 a 는 (fn [x] (* x 2)) 함수로 바뀐다.
user=> (defn a [x] (* x 2))
#'user/a
user=> (a a)

ClassCastException user$a cannot be cast to java.lang.Number clojure.lang.Numbers.multiply (Numbers.java:146)
;; 함수인 a를 받아서 *를 수행하는 clojure.lang.Number.multiply에 전달했으므로, 자동으로 형변환을 할 수 없다고 오류가 발생한다.
}}} [1]> (setq a 4)
4
[2]> (defun a (x) (* x 2))
A
[3]> (a a)
8
}}} [4]> (a #'a)

*** - *: #<FUNCTION A (X) (DECLARE (SYSTEM::IN-DEFUN A)) (BLOCK A (* X 2))> is
not a number
The following restarts are available:
USE-VALUE :R1 Input a value to be used instead.
ABORT :R2 Abort main loop
Break 1 [5]>
}}}

5. SICP와 리스프에 대한 오해

파일:상세 내용 아이콘.svg   자세한 내용은 Structure and Interpretation of Computer Programs 문서
2번 문단을
부분을
참고하십시오.

6. 리스프 사투리

7. 커먼 리스프와 스킴 차이

8. 여담

9. 관련 문서

10. 외부 링크


[1] https://iolanguage.org/ [2] C 언어가 유닉스를 만들기 위해 탄생한 언어라면, LISP는 LISP를 만들기 위해 탄생한 언어라는 농담도 있다. [3] 어차피 모든 범용 프로그래밍 언어는 튜링 완전하기 때문에 기능면에서는 동일하다. 새로운 패러다임의 언어가 등장한다고 해서 전에 없던 완전히 새로운 것이 가능하게 되는 것이 아니고, 그저 표현하는 방식이 바뀌는 것 뿐이며 리스프는 언어 자체가 가지고 있는 이러한 특징을 이용하여 새로운 표현 방식, 문법 등을 embedding 하는 것이 가능하다. 물론 이럴 경우, 항상 실행 효율과 성능이 좋다고 보장할 수 없다. 구현 가능하다는데 의의가 있다. 즉 매크로를 쓰려면 잘 만들어야 한다. [4] Lisp-1 vs Lisp-2 (single-value-space vs multi-value-space) [5] 프로그래밍에서 기술적인 난이도로 가장 어려운 것으로 꼽는 것 중 하나가 바로 이것이다. 여러 프로세스나 쓰레드가 동시에 한 곳에 데이터를 읽고 쓸 때, 통제를 안하면 당연히 값이 엉망이 되는데, 통제하는 게 어려울 뿐더러 성공해도 제대로 못 하면 성능이 극악으로 떨어진다. 이를 효율적으로 잘 하는 것이 관건이다. [6] 이름은 'Leiningen Versus the Ants'라는 단편소설에서 따온 듯하다. 참고로 자바의 대표적인 빌드 툴이 Ant이다. [7] 참고로, 매카시 교수는 ANSI Common Lisp의 스펙이 만들어질 때도 비슷한 요청을 했다고 한다. [8] https://github.com/kimtg/Javelin [9] http://www.newlisp.org/ [10] https://github.com/Academy-City/Railgun [11] https://philip.greenspun.com/bboard/q-and-a-fetch-msg?msg_id=000tgU&topic_id=22&topic=Ask+Philip [12] 그래서, 기존에도 스킴 컴파일러들은 표준적인 부분 이외에 다들 나름의 꽤 커다란 확장을 같이 탑재해서 배포했었다. 이런 경향이 반영된 탓인지, 최근의 표준인 R6RS부터는 더이상 작다고 보긴 힘들어졌는데, 스킴 위원회쪽에서 이런 경향에 반발세력도 꽤 있던 탓인지, 이제는 아예 small scheme, large scheme 두 가지 표준을 운영하는식으로 바뀌어 버렸다. [13] https://www.aladin.co.kr/shop/UsedShop/wuseditemall.aspx?ItemId=13986526&TabType=1 [14] https://exercism.org/tracks?page=1

분류