R6RS Scheme: 라이브러리 형식
R6RS Scheme: 라이브러리 형식
R6RS 라이브러리 정의의 문법을 설명해요. <library> 형식의 구조, <library name>, export·import 명세, 버전 참조 문법, 그리고 가시성·불변성 규칙까지 다뤄요.
출처: 문서
본문
라이브러리 정의는 다음 형식이어야 해요:
(library <library name>
(export <export spec> ...)
(import <import spec> ...)
<library body>)
라이브러리 선언은 다음 요소들을 포함해요:
<library name>은 라이브러리의 이름을 (어쩌면 버전과 함께) 명시해요.export하위 형식은 라이브러리 안에서 정의되었거나 라이브러리로 가져와진 바인딩들의 부분집합에 이름을 붙이는 내보내기 목록을 명시해요.import하위 형식은 가져와진 바인딩들을 가져오기 의존성(import dependency)들의 목록으로 명시하는데, 각 의존성은 다음을 명시해요:- 가져오는 라이브러리의 이름과, 선택적으로, 그것의 버전에 대한 제약,
- 관련 레벨(relevant level), 예를 들어
expand또는run시간(7.2절 참조), 그리고 - 가져오는 라이브러리 안에서 사용할 수 있게 만들 라이브러리 내보내기들의 부분집합과, 라이브러리의 각 내보내기에 대해 가져오는 라이브러리 안에서 사용할 지역 이름들.
<library body>는 라이브러리 본문인데, 정의들의 수열 뒤에 표현식들의 수열로 이루어져 있어요. 이 정의들은 지역(내보내지지 않은) 바인딩과 내보내진 바인딩 둘 다에 대한 것일 수 있고, 표현식들은 그것들의 효과를 위해 평가될 초기화 표현식들이에요.
식별자는 같은 지역 이름으로 두 개 이상의 라이브러리에서 또는 같은 라이브러리에서 두 레벨에 대해, 각 라이브러리가 내보내는 바인딩이 같을 때에만(즉, 그 바인딩이 한 라이브러리에서 정의되고 가져오기를 통해 내보내기와 재-내보내기에 의해서만 도착할 때) 가져와질 수 있어요. 그렇지 않으면 어떤 식별자도 여러 번 가져와지거나, 여러 번 정의되거나, 정의되고 가져와지는 것 둘 다가 될 수 없어요. 라이브러리 안에서 보이는 식별자는 명시적으로 라이브러리로 가져와진 것이나 라이브러리 안에서 정의된 것뿐이에요.
<library name>은 구현 안에서 라이브러리를 고유하게 식별하며, 구현 안의 다른 모든 라이브러리의 import 절(아래 참조)에서 전역적으로 보여요. <library name>은 다음 형식을 가져요:
(<identifier> ... <version>)
여기서 <version>은 비어 있거나 다음 형식을 가져요:
(<sub-version> ...)
각 <sub-version>은 정확한 음이 아닌 정수 객체를 나타내야 해요. 빈 <version>은 ()와 동등해요.
<export spec>은 내보낼, 어쩌면 다른 외부 이름을 가진, 가져와지고 지역적으로 정의된 바인딩들의 집합에 이름을 붙여요. <export spec>은 다음 형식 중 하나여야 해요:
<identifier>
(rename (<identifier1> <identifier2>) ...)
<export spec>에서 <identifier>는 라이브러리 안에서 정의되었거나 가져와진 단일 바인딩에 이름을 붙이는데, 그 내보내기의 외부 이름은 라이브러리 안의 바인딩의 이름과 같아요. rename 명세는 각 (<identifier1> <identifier2>) 짝에서 <identifier1>이 이름 붙이는 바인딩을 <identifier2>를 외부 이름으로 사용하여 내보내요.
각 <import spec>은 라이브러리로 가져올 바인딩들의 집합, 그것들이 사용할 수 있게 될 레벨들, 그리고 그것들이 알려질 지역 이름들을 명시해요. <import spec>은 다음 중 하나여야 해요:
<import set>
(for <import set> <import level> ...)
<import level>은 다음 중 하나예요:
run
expand
(meta <level>)
여기서 <level>은 정확한 정수 객체를 나타내요.
<import level>으로서 run은 (meta 0)의 약자이고 expand는 (meta 1)의 약자예요. 레벨과 위상(phase)은 7.2절에서 논의돼요.
<import set>은 다른 라이브러리에서 바인딩들의 집합에 이름을 붙이고 어쩌면 가져와진 바인딩들에 대한 지역 이름을 명시해요. 그것은 다음 중 하나여야 해요:
<library reference>
(library <library reference>)
(only <import set> <identifier> ...)
(except <import set> <identifier> ...)
(prefix <import set> <identifier>)
(rename <import set> (<identifier1> <identifier2>) ...)
<library reference>는 라이브러리를 그것의 이름으로 그리고 선택적으로 그것의 버전으로 식별해요. 그것은 다음 형식 중 하나를 가져요:
(<identifier> ...)
(<identifier1> <identifier2> ... <version reference>)
첫 번째 <identifier>가 for, library, only, except, prefix, 또는 rename인 <library reference>는 library <import set> 안에서만 허용돼요. <import set> (library <library reference>)는 그 외에는 <library reference>와 동등해요.
<version reference>가 없는 <library reference>(위의 첫 번째 형식)는 <version reference>가 ()인 <library reference>와 동등해요.
<version reference>는 그것이 일치하는 <version>들의 집합을 명시해요. <library reference>는 같은 이름을 가지고 그 버전이 <version reference>에 일치하는 모든 라이브러리를 식별해요. <version reference>는 다음 형식을 가져요:
(<sub-version reference> ...)
(and <version reference> ...)
(or <version reference> ...)
(not <version reference>)
첫 번째 형식의 <version reference>는 적어도 n개의 원소를 가진 <version>에 일치하는데, 그 <sub-version reference>들이 대응하는 <sub-version>들에 일치해요. and <version reference>는 and 뒤의 모든 <version reference>들이 일치하면 그 버전에 일치해요. 대응되게, or <version reference>는 or 뒤의 <version reference>들 중 하나가 일치하면 그 버전에 일치하고, not <version reference>는 그 뒤의 <version reference>가 일치하지 않으면 그 버전에 일치해요.
<sub-version reference>는 다음 형식 중 하나를 가져요:
<sub-version>
(>= <sub-version>)
(<= <sub-version>)
(and <sub-version reference> ...)
(or <sub-version reference> ...)
(not <sub-version reference>)
첫 번째 형식의 <sub-version reference>는 <sub-version>의 >= <sub-version reference>가 그 뒤의 <sub-version>보다 크거나 같으면 (그 <sub-version>과) 같다면 그 하위 버전에 일치해요. <= <sub-version reference>에 대해서도 유사하게 일치해요. and, or, not <sub-version reference>는 <version reference>에 대한 그것들과 같은 방식으로 일치해요.
예:
(library (rnrs base (6)))
(library (my-lib)
(import (only (rnrs base) display))
(export say-hello)
...)
(library (util (2)))
(import (only (rnrs base) car cdr cons null? pair?))
(export (rename (my-cons cons)))
...)
라이브러리 참조가 하나보다 많은 라이브러리를 식별하면, 라이브러리의 선택은 어떤 구현 의존 방식으로 결정돼요.
호환되지 않는 타입과 복제된 상태 같은 문제들을 피하기 위해, 구현들은 같은 식별자 수열로 이루어진 라이브러리 이름을 가지지만 버전이 일치하지 않는 두 라이브러리가 같은 프로그램에 공존하는 것을 금지해야 해요.
기본적으로, 가져온 라이브러리의 모든 내보내진 바인딩은 가져온 라이브러리가 바인딩들에 준 이름들을 사용하여 가져오는 라이브러리 안에서 보이게 돼요. 가져올 바인딩들의 정확한 집합과 그 바인딩들의 이름은 아래에서 설명하는 only, except, prefix, rename 형식으로 조정될 수 있어요.
only형식은 나열된<identifier>들만 포함하여 다른<import set>의 바인딩들의 부분집합을 만들어내요. 포함되는<identifier>들은 원래의<import set>에 있어야 해요.except형식은 나열된<identifier>들을 제외한 모든 것을 포함하여 다른<import set>의 바인딩들의 부분집합을 만들어내요. 제외되는 모든<identifier>들은 원래의<import set>에 있어야 해요.prefix형식은 다른<import set>의 각 이름에<identifier>접두사를 더해요.rename형식,(rename (<import set> (<identifier1> <identifier2>) ...))은<import set>의 bindings 제거해 중간<import set>을 만들고, 그런 다음 대응하는<identifier2>들에 대한 바인딩들을 다시 추가해 최종<import set>을 만들어요. 각<identifier1>은 원래의<import set>에 있어야 하고, 각<identifier2>는 중간<import set>에 없어야 하며,<identifier2>들은 서로 달라야 해요.
위에서 주어진 제약이 충족되지 않으면 문법 위반이에요.
library 형식의 <library body>는 정의(definitions) 또는 표현식(expressions)으로 분류되는 형식들로 이루어져 있어요. 어떤 형식이 어느 분류에 속하는지는 가져온 라이브러리들과 확장의 결과에 달려 있어요 — 10장 참조. 일반적으로, 정의가 아닌 형식(기본 라이브러리를 통해 사용할 수 있는 정의에 대한 11.2절 참조)은 표현식이에요.
<library body>는 <body>(11.3절 참조)와 같되, <library body>들은 어떤 표현식도 포함할 필요가 없다는 점이 달라요. 그것은 다음 형식이어야 해요:
<definition> ... <expression> ...
begin, let-syntax, 또는 letrec-syntax 형식이 첫 표현식 앞의 최상위 본문에서 발생하면 그것들은 본문에 접합(splice)돼요. (11.4.7절 참조) 본문의 일부 또는 전부는, begin, let-syntax, letrec-syntax 형식으로 감싸인 부분을 포함해, 문법 추상화(9.2절 참조)로 명시될 수 있어요.
변환기 표현식들과 바인딩들은 10장에서 설명한 대로 왼쪽에서 오른쪽으로 평가·생성돼요. 변수 정의들의 표현식들은 암묵적인 letrec*에서처럼 왼쪽에서 오른쪽으로 평가되고, 본문 표현식들도 변수 정의들의 표현식들 뒤에 왼쪽에서 오른쪽으로 평가돼요. 각 내보내진 변수에 대해 새 위치(location)가 만들어지고 그것의 지역 대응물의 값으로 초기화돼요. 마지막 본문 표현식의 연속체로 두 번 되돌아가는 효과는 미지정이에요.
Note: 라이브러리 문법에 나타나는
library,export,import,for,run,expand,meta,only,except,prefix,rename,and,or,not,>=,<=이름들은 문법의 일부이며 예약되지 않아요. 즉, 같은 이름들을 라이브러리 안의 다른 목적에 사용하거나, 다른 의미로 라이브러리에서 내보내거나 라이브러리로 가져올 수도 있는데,library형식에서의 사용에는 영향을 주지 않아요.
라이브러리로 정의된 바인딩들은, 명시적으로 라이브러리에서 내보내지 않는 한, 라이브러리 밖의 코드에서 보이지 않아요. 그러나 내보내진 매크로는 그렇지 않으면 내보내지지 않은, 라이브러리 안에서 정의되었거나 라이브러리로 가져와진 식별자를 암묵적으로 내보낼 수 있어요. 즉, 그것이 만들어내는 출력 코드에 그 식별자에 대한 참조를 삽입할 수 있어요.
명시적으로 내보내진 모든 변수는 내보내는 라이브러리와 가져오는 라이브러리 둘 다에서 불변(immutable)이에요. 따라서 명시적으로 내보내진 변수가 내보내는 라이브러리 또는 가져오는 라이브러리에서 set! 표현식의 왼쪽에 나타나면 문법 위반이에요.
암묵적으로 내보내진 모든 변수도 내보내는 라이브러리와 가져오는 라이브러리 둘 다에서 불변이에요. 따라서 내보내진 매크로가 그 변수가 정의된 라이브러리 밖에서 만들어낸 어떤 코드에 변수가 set! 표현식의 왼쪽에 나타나면 문법 위반이에요. 내보내진 매크로가 그 변수가 정의된 라이브러리 밖에서 만들어낸 어떤 코드에 대입된 변수(assigned variable, 즉 내보내는 라이브러리의 set! 표현식의 왼쪽에 나타나는 변수)에 대한 참조가 나타나는 것도 문법 위반이에요.
라이브러리 안에서 정의된 다른 모든 변수는 가변(mutable)이에요.