리더 조건부
리더 조건부 (Reader Conditionals)
Clojure 1.7은 여러 Clojure 플랫폼이 로드할 수 있는 이식 가능한 파일을 위한 새 확장자(.cljc)를 도입했어요. 플랫폼 특정 코드를 관리하는 주요 메커니즘은 그 코드를 최소한의 네임스페이스 집합으로 격리하고, 그 네임스페이스의 플랫폼 특정 버전(.clj/.class 또는 .cljs)을 제공하는 거예요.
코드의 변하는 부분을 격리하는 것이 실현 불가능한 경우나, 코드가 대부분 이식 가능하고 작은 플랫폼 특정 부분만 있는 경우, 1.7은 리더 조건부(reader conditionals) 또한 도입했어요. 이것은 cljc 파일과 기본 REPL에서만 지원돼요. 리더 조건부는 드물게 그리고 필요한 경우에만 사용해야 해요.
리더 조건부는 pass:[#?] 또는 pass:[#?@]로 시작하는 새 리더 디스패치 폼이에요. 둘 다 cond와 비슷하게, 번갈아 나타나는 특징(features)과 표현식들의 연속으로 구성돼요. 모든 Clojure 플랫폼은 잘 알려진 "플랫폼 특징" — :clj, :cljs, :cljr — 을 가져요. 리더 조건부의 각 조건은 플랫폼 특징과 일치하는 특징을 찾을 때까지 순서대로 검사돼요. 리더 조건부는 그 특징의 표현식을 읽고 반환해요. 선택되지 않은 각 분기의 표현식은 읽히지만 건너뛰어져요. 잘 알려진 :default 특징은 항상 일치하며 기본값을 제공하는 데 사용할 수 있어요. 어떤 분기도 일치하지 않으면, 어떤 폼도 읽히지 않아요(리더 조건부 표현식이 없었던 것처럼).
참고: 공식이 아닌 Clojure 플랫폼의 구현자는 이름 충돌을 피하려면 플랫폼 특징에 한정된 키워드를 사용해야 해요. 한정되지 않은 플랫폼 특징은 공식 플랫폼을 위해 예약돼요.
다음 예시는 Clojure에서는 Double/NaN으로, ClojureScript에서는 js/NaN으로, 다른 어떤 플랫폼에서는 nil로 읽혀요:
#?(:clj Double/NaN
:cljs js/NaN
:default nil)
pass:[#?@]의 문법은 정확히 같지만, 표현식이 둘러싼 컨텍스트에 스플라이스(splice)될 수 있는 컬렉션을 반환할 것으로 예상돼요. 신택스 쿼트의 unquote-splicing과 비슷해요. 최상위에서 리더 조건부 스플라이싱의 사용은 지원되지 않으며 예외를 던져요. 예시:
[1 2 #?@(:clj [3 4] :cljs [5 6])]
;; in clj => [1 2 3 4]
;; in cljs => [1 2 5 6]
;; anywhere else => [1 2]
read와 read-string 함수는 선택적으로 옵션 맵을 첫 번째 인자로 받아요. 현재 특징 집합과 리더 조건부 동작은 옵션 맵에서 다음 키와 값으로 설정할 수 있어요:
:read-cond - :allow to process reader conditionals, or
:preserve to keep all branches
:features - persistent set of feature keywords that are active
Clojure에서 ClojureScript 리더 조건부를 테스트하는 방법의 예시:
(read-string
{:read-cond :allow
:features #{:cljs}}
"#?(:cljs :works! :default :boo)")
;; :works!
그러나 Clojure 리더는 항상 플랫폼 특징 :clj도 주입한다는 점에 주의하세요. 플랫폼-무관한 읽기를 보려면 tools.reader를 참고하세요.
리더가 {:read-cond :preserve}로 호출되면, 리더 조건부와 실행되지 않은 분기들이 데이터로 반환된 폼에 보존돼요. 리더-조건부는 키에 :form과 :splicing? 플래그에 대한 키워드 검색을 지원하는 타입으로 반환돼요. 읽혔지만 건너뛴 태그된 리터럴은 키에 :form과 :tag 키에 대한 키워드 검색을 지원하는 타입으로 반환돼요.
(read-string
{:read-cond :preserve}
"[1 2 #?@(:clj [3 4] :cljs [5 6])]")
;; [1 2 #?@(:clj [3 4] :cljs [5 6])]
다음 함수들도 이 타입들의 술어나 생성자로 사용할 수 있어요: +
reader-conditional? reader-conditional tagged-literal? tagged-literal