접힐 수 있는 계약

접힐 수 있는 계약 (Collapsible Contracts)

고차 값에 계약 래퍼가 병리적으로 쌓여 가는 문제를 피하기 위해 계약 시스템이 제공하는 최적화가 접힐 수 있는(collapsible) 계약이에요. 이 문서에서는 그 내부 구조와 관련 함수들을 설명할게요.

출처: Racket Reference

본문

8.10 접힐 수 있는 계약

(require racket/contract/collapsible)

package: base

Added in version 7.1.0.10 of package base.

접힐 수 있는 계약은 고차 값에 계약 래퍼가 병리적으로 쌓이는 특정 상황을 피하기 위해 계약 시스템에 설계된 최적화입니다. vectorof, vector/c, -> 계약 조합자들은 벡터 계약과, 단일 값을 반환하는 함수의 함수 계약에 대해 접기(collapsing)를 지원합니다.

직관적으로, 접힐 수 있는 계약은 트리 구조입니다. 트리 노드는 고차 계약(예: ->)을 나타내고, 트리 리프는 평탄(flat) 계약들의 시퀀스를 나타냅니다. 두 트리는 merge 프로시저를 통해 하나의 트리로 접힐 수 있는데, 이 프로시저는 리프에서 불필요한 평탄 계약들을 제거합니다.

접힐 수 있는 계약의 동기와 설계에 대한 더 자세한 정보는 [Feltey18]을, 이론적 기초는 [Greenberg15]를 참고하세요.

경고: 이 섹션에 설명된 기능들은 실험적이며, 새 접힐 수 있는 계약을 구현하기에 충분하지 않을 수 있습니다. 새 접힐 수 있는 계약을 구현하려면 벡터와 프로시저 값에 대해서만 지원되는 불안전한(unsafe) chaperone과 impersonator를 사용해야 해요. 이 문서는 주로 racket/contract/collapsible 라이브러리의 향후 유지보수를 위해 존재합니다. 경고 끝.

get/build-collapsible-late-neg-projection

(get/build-collapsible-late-neg-projection c)
 → (-> blame? (values (-> any/c any/c any/c) collapsible-contract?))
  c : contract?

c에 대한 접힐 수 있는 late-neg 투영(projection)을 반환합니다. c에 접힐 수 있는 late-neg 투영이 없으면, 이 함수는 그것을 위해 원래 투영을 사용하고 리프를 접힐 수 있는 표현으로 구성합니다.

collapsible-contract-continuation-mark-key

collapsible-contract-continuation-mark-key : continuation-mark-key?

접힐 수 있는 계약 검사 중에 존재하는 continuation mark가 사용하는 키입니다. 현재 계약이 접힐 수 있으면 이 마크의 값은 #t입니다.

with-collapsible-contract-continuation-mark

(with-collapsible-contract-continuation-mark body ...)

현재 계약이 접힐 수 있음을 계약 프로파일러에 알리는 continuation mark를 삽입합니다.

prop:collapsible-contract

prop:collapsible-contract : struct-type-property?

이 속성을 구현하는 구조체들은 접힐 수 있는 계약으로 사용할 수 있습니다. 이 속성과 연결된 값은 build-collapsible-contract-property를 호출해 구성해야 합니다.

collapsible-contract?

(collapsible-contract? v) → boolean?
  v : any/c

prop:collapsible-contract 속성을 가진 구조체를 인식하는 서술어입니다.

merge

(merge new-cc new-neg old-cc old-neg) → collapsible-contract?
  new-cc : collapsible-contract?
  new-neg : any/c
  old-cc : collapsible-contract?
  old-neg : any/c

두 접힐 수 있는 계약을 하나의 접힐 수 있는 계약으로 결합합니다. new-negold-neg 인자는 late-neg 투영에 전달되는 것과 비슷한 blame 당사자(party)로 기대됩니다.

collapsible-guard

(collapsible-guard cc val neg-party) → any/c
  cc : collapsible-contract?
  val : any/c
  neg-party : any/c

late-neg 투영과 비슷하게, 이 함수는 값 val을 접힐 수 있는 계약 cc로 보호(guard)합니다.

collapsible-contract-property?

(collapsible-contract-property? v) → boolean?
  v : any/c

이 서술어는 값이 prop:collapsible-contract의 속성으로 사용될 수 있음을 나타냅니다.

build-collapsible-contract-property

(build-collapsible-contract-property
  [#:try-merge try-merge
   #:collapsible-guard collapsible-guard])
 → collapsible-contract-property?

  try-merge : (or/c #f
                   (-> collapsible-contract?
                       any/c
                       collapsible-contract?
                       any/c
                       (or/c #f collapsible-contract?)))
            = #f

  collapsible-guard : (-> collapsible-contract? any/c any/c any/c)
                   = (λ (cc v neg)
                       (error
                        "internal error: contract does not support `collapsible-guard`" cc))

병합(merging) 함수와 가드(guard)로부터 접힐 수 있는 계약 속성을 구성합니다. try-merge 인자는 merge와 비슷하지만, 접힐 수 있는 계약 대신 #f를 반환할 수 있고 특정 접힐 수 있는 계약에 특화(specialized)될 수 있습니다. collapsible-guard 인자는 구현 중인 특정 접힐 수 있는 계약에 특화되어야 합니다.

struct collapsible-ho/c

(struct collapsible-ho/c (latest-blame missing-party latest-ctc))
  latest-blame : blame?
  missing-party : any/c
  latest-ctc : contract?

고차 값을 위한 접힐 수 있는 계약들의 공통 부모 구조체입니다. latest-blame 필드는 가장 최근에 붙은 계약의 blame 객체를 담고 있습니다. 마찬가지로 missing-party 필드는 계약에 전달된 가장 최근의 missing 당사자를 담습니다. latest-contract 필드는 값에 가장 최근에 붙은 계약을 저장합니다.

struct collapsible-leaf/c

(struct collapsible-leaf/c (proj-list contract-list blame-list missing-party-list))
  proj-list : (listof (-> any/c any/c any/c))
  contract-list : (listof contract?)
  blame-list : (listof blame?)
  missing-party-list : (listof any/c)

접힐 수 있는 계약의 리프 노드를 나타내는 구조체입니다. proj-list 필드는 부분 적용된 late-neg 투영들의 리스트를 담고, contract-list, blame-list, missing-party-list 필드는 각각 계약 리스트, blame 객체 리스트, blame missing 당사자 리스트를 담습니다.

impersonator-prop:collapsible

impersonator-prop:collapsible : impersonator-property?

(has-impersonator-prop:collapsible? v) → boolean?
  v : any/c

(get-impersonator-prop:collapsible v) → collapsible-property?
  v : any/c

접힐 수 있는 계약으로 보호(guard)된 chaperone되거나 impersonate된 값에 붙여야 하는 임퍼서네이터 속성(과 그 접근자)입니다.

struct collapsible-property

(struct collapsible-property (c-c neg-party ref))
  c-c : collapsible-contract?
  neg-party : any/c
  ref : (or/c #f impersonator?)

접힐 수 있는 계약으로 보호된 값의 chaperone이나 impersonator에 붙여야 하는 속성들의 부모 구조체입니다. c-c 필드는 값에 붙어 있거나 향후 붙을 접힐 수 있는 계약을 저장합니다. neg-party 필드는 값이 달린 계약에 전달된 가장 최근의 missing blame 당사자를 저장합니다. ref 필드는 가변하며, 이 속성이 붙은 chaperone이나 impersonator에 대한 참조를 저장합니다. 이는 값이 접힐 수 있는 계약으로 보호된 후에 알려지지 않은 chaperone이 값에 붙었는지 판단하기 위해 필요합니다.

struct collapsible-count-property

(struct collapsible-count-property collapsible-property (count prev))
  count : natural-number/c
  prev : (or/c collapsible-count-property? any/c)

이 속성은 값이 완전히 접힘 모드에 들어가기 전에 impersonator-prop:collapsible 속성과 연관됩니다. 이 속성들은 count 필드에 값에 붙은 계약의 개수를 추적하고, prev 필드에 이전 count 속성에 대한 참조를, 또는 계약이 없는 원래 값을 담습니다. 이를 통해 계약 시스템은 붙은 계약들의 체인을 따라가며 그것들을 단일 접힐 수 있는 계약으로 병합해 원래 값을 보호할 수 있습니다.

struct collapsible-wrapper-property

(struct collapsible-wrapper-property collapsible-property (checking-wrapper))
  checking-wrapper : impersonator?

이 속성은 값이 접힐 수 있는 계약으로 보호될 때 사용됩니다. checking-wrapper 필드는 이 속성에 저장된 접힐 수 있는 계약으로 디스패치해 필요한 계약 검사를 수행하는 chaperone이나 impersonator를 담고 있습니다. 값이 다른 계약을 받아 병합이 일어나면, 값에 붙은 특정 접힐 수 있는 계약이 바뀌어도 checking wrapper는 동일하게 유지됩니다.

더 알아보기