다른 Lisp들과의 차이점

다른 Lisp들과의 차이점 (Differences with other Lisps)

이 정보는 Common Lisp나 Scheme에 익숙한 프로그래머를 위해 제공돼요.

  • Clojure는 대소문자를 구분해요 (case sensitive)
  • Clojure는 Lisp-1이에요
  • ()는 nil과 같지 않아요
  • 리더(reader)는 부수 효과가 없어요
  • 키워드(keyword)는 심볼이 아니에요
  • 심볼은 저장 위치(storage location)가 아니에요 (Var 참고)
  • nil은 심볼이 아니에요
  • t는 문법이 아니에요 — true를 쓰세요
  • 읽기 테이블(read table)은 사용자 프로그램이 접근할 수 없어요
  • let은 순차적으로 바인딩해요
  • do는 반복 구성소가 아니에요
  • 꼬리 호출 최적화(tail-call optimization)가 없어요 — recur를 사용하세요.
  • syntax-quote는 심볼 해석(resolution)을 수행하므로 `x'x와 같지 않아요.
  • `(backtick)은 자동 젠심(automatic gensym)을 제공해요.
  • ~는 언쿼트(unquote)이고 ,는 공백(whitespace)이에요
  • 맵, 벡터, 집합을 위한 리더 문법(reader syntax)이 있어요
  • cons, first, rest는 구체적인 cons 셀(cell)이 아니라 시퀀스 추상화(sequence abstraction)를 다뤄요
  • 대부분의 데이터 구조는 불변(immutable)이에요
  • lambda는 fn이며, 인자 수(arity)에 따른 오버로딩을 지원해요
  • =는 동등성(equality) 술어예요
  • 전역 Var는 (dynamic으로 선언되어 있다면) 어휘적(lexical) 지역 바인딩을 방해하지 않고 동적으로 다시 바인딩될 수 있어요. 동적 바인딩과 어휘적 바인딩을 구분하는 데 특별한 선언은 필요 없어요. Clojure는 Lisp-1이므로 (전역) 함수도 (dynamic으로 표시되어 있다면) 동적으로 다시 바인딩될 수 있어요.
  • letrec, labels, flet은 없어요 — 자기 참조에는 (fn name [args]...)을, 상호 참조에는 letfn을 사용하세요.
  • Clojure에서 nil은 '아무것도 없음(nothing)'을 뜻해요. 어떤 타입이든 값이 없음을 나타내며, 리스트나 시퀀스에만 국한되지는 않아요.
  • 빈 컬렉션은 nil과 구별돼요. Clojure는 nil'()를 동일시하지 않아요.
  • false는 두 가능한 불리언 값 중 하나를 뜻하고, 다른 하나는 true예요
  • 컬렉션에는 리스트보다 더 많은 것이 있어요. 빈 컬렉션의 인스턴스를 가질 수 있고, 그중 일부는 리터럴 지원([], {}, ())을 가져요. 따라서 센티널(sentinel) 빈 컬렉션 값은 존재할 수 없어요.
  • Scheme에서 온 사람이라면, nil이 여러분의 #f 관념에 가장 가깝게 매핑될 거예요.
  • Clojure의 큰 차이점은 시퀀스예요. 시퀀스는 특정 컬렉션이 아니며, 특히 반드시 구체적인 리스트일 필요는 없어요. 빈 컬렉션에 그 요소들의 시퀀스를 요청하면(seq 호출) nil을 반환하며 "하나를 만들어 낼 수 없어요"라고 말하는 거죠. 시퀀스의 마지막 요소에 rest를 요청하면 _또 다른 논리적 시퀀스_를 반환해요. 그 시퀀스가 비었는지는 그 시퀀스에 다시 seq를 호출해야만 알 수 있어요. 이 덕분에 시퀀스와 시퀀스 프로토콜이 지연(lazy) 될 수 있어요.
  • 일부 시퀀스 함수는 Scheme과 CL에서 '리스트'(pair/cons)만 조작하고 '빈' 리스트를 나타내는 센티널 값('()nil)을 반환했던 함수들에 대응해요. Clojure의 반환 값은 구체적인 빈 컬렉션을 반환하지 않고 오히려 또 다른 논리적 시퀀스를 반환한다는 점에서 달라요. 일부 시퀀스 함수는 Scheme/CL에 대응물이 없고, Haskell/ML 류 함수에 매핑돼요. 그런 함수 중 일부는 무한하거나 계산된 시퀀스를 반환하는데, 여기서 Scheme/CL 리스트 같은 구체적 데이터 구조와의 비유는 매우 희박해져요.
  • 컬렉션/데이터 구조와 seq/반복을 구분하는 게 도움이 돼요. CL과 Scheme에서는 둘이 혼동되지만, Clojure에서는 별개예요.
Clojure Common Lisp Scheme Java
nil이 있나? nil - 'nothing'을 뜻함 nil - false 또는 빈 리스트를 뜻함 - null
true가 있나? true - #t true (원시 타입)
false가 있나? false - #f false (원시 타입)
조건식이 구분하는 것: nil 또는 false / 그 외 전부 nil/non-nil #f/non-#f false/true
리스트/시퀀스 라이브러리가 구별되는 구체 타입을 조작하나? 아니요 - 여러 컬렉션 구현을 가진 seq 추상화 예 - cons와 vector 예 - pair 아니요 - 여러 컬렉션 구현을 가진 Iterator 추상화
싱글턴 빈 리스트 값? 아니요 - 구체 컬렉션 타입의 구별되는 빈 값을 가질 수 있음 nil '() 아니요
시퀀스 끝 반환값: seq가 nil을 반환하는 논리적 시퀀스 nil '() false
호스트 null: nil 해당 없음 해당 없음 해당 없음
호스트 true: true (박싱됨) 해당 없음 해당 없음 해당 없음
호스트 false: false (박싱됨) 해당 없음 해당 없음 해당 없음

출처: 다른 Lisp들과의 차이점 (Differences with other Lisps)

더 알아보기