계약

계약

계약(contract)은 프로그램의 한 부분이 다른 부분을 서로 보호하도록 하는 시스템이에요. 프로그래머는 모듈의 내보내기(export) 동작을 (provide (contract-out ...)) 또는 (require (contract-in ...))으로 명시하고, 계약 시스템이 그 제약을 강제해요.

계약은 두 가지 형태로 나뉘어요. 하나는 이 매뉴얼의 이 절에서 나열하는 여러 연산으로 만들어진 계약이고, 다른 하나는 계약으로도 쓰이는 여러 일반 Racket 값이에요.

출처: Racket Reference

본문

계약 시스템은 프로그램의 한 부분이 다른 부분을 서로 보호하게 해줘요. 프로그래머는 모듈의 내보내기 동작을 (provide (contract-out ...)) 또는 (require (contract-in ...))으로 명시하고, 계약 시스템이 그 제약을 강제해요.

(require racket/contract)

package: base

이 절에서 다루는 바인딩은 racket/contractracket 라이브러리가 제공하지만, racket/base는 제공하지 않아요.

계약은 두 가지 형태로 나뉘어요.

  • 이 매뉴얼의 이 절에 나열된 여러 연산으로 만들어진 계약, 그리고
  • 계약으로도 쓰이는 여러 일반 Racket 값.

계약으로 겸용되는 Racket 값들에는 다음이 있어요.

  • 심볼, 불리언, 키워드, 그리고 null. 이들은 eq?를 사용해 스스로를 인식하는 계약으로 취급돼요.
  • 문자열, 바이트 문자열, 문자, +nan.0, +nan.f. 이들은 equal?를 사용해 스스로를 인식하는 계약으로 취급돼요.
  • 수(+nan.0+nan.f 제외). 이들은 =를 사용해 스스로를 인식하는 계약으로 취급돼요.
  • 정규 표현식. 이들은 그 정규 표현식과 일치하는 바이트 문자열과 문자열을 인식하는 계약으로 취급돼요.
  • 술어(predicate): 인자 1개를 받는 임의의 프로시저는 술어로 취급돼요. 계약 검사 중에 그 프로시저가 나타나는 값들에 적용되며, #f를 돌려주면 계약이 실패했다는 뜻이고 그 외의 값은 통과를 뜻해요.

계약 결합자(combinator)는 ->listof 같은 함수로, 계약을 받아 다른 계약을 만들어내요.

Racket의 계약은 다음 세 가지 범주로 세분화돼요.

플랫(Flat) 계약은 주어진 값에 대해 즉시 완전히 검사할 수 있어요. 이런 계약은 본질적으로 술어 함수예요. flat-contract-predicate를 사용하면 임의의 플랫 계약에서 술어를 추출할 수 있고, 어떤 플랫 계약은 함수처럼 적용될 수도 있는데, 그 경우 단일 인자를 받아 그 값이 계약에 받아들여질지 #t#f로 돌려줘요. 이 라이브러리의 함수들이 돌려주는 모든 플랫 계약은 직접 술어로 사용할 수 있지만, 수나 심볼처럼 플랫 계약으로 겸용되는 일반 Racket 값은 그럴 수 없어요.

flat-contract? 함수는 플랫 계약을 인식해요.

채퍼론(Chaperone) 계약은 값이 사용될 때 나중에 계약 위반을 알리도록 값을 감쌀 수 있지만, 그 외의 동작은 바꾸지 않음을 보장해요. 예를 들어 함수 계약은 함수 값을 감싸 나중에 입력과 출력을 검사해요. 함수 값이 계약으로 감싸지기 전에 가졌던 속성들은 계약 래퍼가 보존해요.

모든 플랫 계약은 채퍼론 계약이 필요할 자리에 사용할 수 있어요(반대는 안 돼요). chaperone-contract? 함수는 채퍼론 계약을 인식해요.

인페르소네이터(Impersonator) 계약은 값을 감쌀 수 있지만 아무런 보장도 제공하지 않아요. 인페르소네이터 계약은 값의 속성을 숨기거나 완전히 불투명하게 만들 수도 있어요(예: new-∀/c).

모든 계약은 인페르소네이터 계약이 필요할 자리에 사용할 수 있어요. impersonator-contract? 함수는 인페르소네이터 계약을 인식해요.

이 계층 구조에 대한 자세한 내용은 "Impersonators and Chaperones" 절과, 채퍼론·인페르소네이터 그리고 이들이 계약 구현에 어떻게 쓰이는지에 관한 연구 논문 [Strickland12]를 참고해요.

package base 버전 6.1.1.8에서 변경됨: +nan.0+nan.fequal? 기반 계약으로 변경했어요.

아래는 계약의 하위 주제 목록이에요.

8.1 데이터 구조 계약 (Data-structure Contracts)
8.2 함수 계약 (Function Contracts)
8.3 매개변수 계약 (Parametric Contracts)
8.4 지연 데이터 구조 계약 (Lazy Data-structure Contracts)
8.5 구조체 타입 속성 계약 (Structure Type Property Contracts)
8.6 값에 계약 붙이기 (Attaching Contracts to Values)
8.6.1 중첩 계약 경계 (Nested Contract Boundaries)
8.6.2 저수준 계약 경계 (Low-level Contract Boundaries)
8.7 새 계약 결합자 만들기 (Building New Contract Combinators)
8.7.1 Blame 객체 (Blame Objects)
8.7.2 계약을 구조체로 (Contracts as structs)
8.7.3 Check Syntax의 책임 정보 (Obligation Information in Check Syntax)
8.7.4 새 결합자 만들기를 위한 유틸리티 (Utilities for Building New Combinators)
8.8 계약 유틸리티 (Contract Utilities)
8.9 racket/contract/base
8.10 접힐 수 있는 계약 (Collapsible Contracts)
8.11 레거시 계약 (Legacy Contracts)
8.12 랜덤 생성 (Random generation)

더 알아보기