프로시저

프로시저 (Procedures)

프로시저는 Racket에서 함수를 나타내는 값이에요. procedure?로 확인하고, apply로 인자 목록을 넘겨 호출하며, compose로 합성할 수 있어요. 프로시저의 인자 개수(arity)와 키워드 프로토콜을 조사하고 조정하는 다양한 프로시저도 제공해요.

출처: Racket Reference

본문

4.20 프로시저

procedure

(procedure? v) → boolean?
  v : any/c

v가 프로시저이면 #t를, 그렇지 않으면 #f를 반환해요.

procedure

(apply proc v ... lst #:<kw> kw-arg ...) → any
  proc : procedure?
  v : any/c
  lst : list?
  kw-arg : any/c

Racket 가이드의 "apply 함수" 절에서 apply를 소개해요.

(list* v ... lst)의 내용을 (위치 기반) 인자로 사용해 proc을 적용해요. #:<kw> kw-arg 수열도 proc에 키워드 인자로 제공되며, 여기서 #:<kw>는 임의의 키워드를 나타내요.

주어진 procv 개수에 lst의 길이를 더한 만큼의 인자를 받아야 하고, 제공된 키워드 인자를 받아야 하며, 다른 키워드 인자를 요구해서는 안 돼요. 그렇지 않으면 exn:fail:contract 예외가 발생해요. 주어진 procapply 호출에 대해 꼬리 위치에서 호출돼요.

예시:

> (apply + '(1 2 3))
6
> (apply + 1 2 '(3))
6
> (apply + '())
0
> (apply sort (list (list '(2) '(1)) <) #:key car)
'((1) (2))

procedure

(compose proc ...) → procedure?
  proc : procedure?

procedure

(compose1 proc ...) → procedure?
  proc : procedure?

주어진 함수들을 합성하는 프로시저를 반환해요. 마지막 proc을 먼저 적용하고 첫 proc을 마지막에 적용해요. compose 함수는 주어진 함수들이 임의 개수의 값을 소비하고 생산할 수 있게 하며, 각 함수가 앞의 함수가 소비하는 만큼의 값을 생산하기만 하면 돼요. 반면 compose1은 내부 값 전달을 단일 값으로 제한해요. 두 경우 모두 마지막 함수의 입력 개수(arity)와 첫 함수의 출력 개수는 제한이 없으며, 이것들이 결과 합성 함수의 해당 개수가 돼요(입력 쪽의 키워드 인자 포함).

proc 인자가 없으면 결과는 values예요. 정확히 하나가 주어지면 그것이 반환돼요.

예시:

> ((compose1 - sqrt) 10)
-3.1622776601683795
> ((compose1 sqrt -) 10)
0.0+3.1622776601683795i
> ((compose list split-path) (bytes->path #"/a" 'unix))
'(#<path:/> #<path:a> #f)

많은 경우 compose1이 선호된다는 점을 기억하세요. 예를 들어 compose를 두 라이브러리 함수와 함께 사용하면, 한 함수가 두 값을 반환하도록 확장되고 앞의 함수가 의미가 다른 선택적 입력을 가질 때 문제가 생길 수 있어요. 또한 compose1이 더 빠른 합성 함수를 만들 수 있어요.

procedure

(procedure-rename proc name [realm]) → procedure?
  proc : procedure?
  name : symbol?
  realm : symbol? = 'racket

proc과 같지만, object-name이 반환하는(그리고 디버깅용으로 출력되는) 이름이 name이고, (오류 메시지 조정에 잠재적으로 사용되는) realm이 realm인 프로시저를 반환해요.

주어진 namerealm은 결과 프로시저가 잘못된 인자 수로 적용될 때 출력 및 오류 메시지 조정에 사용돼요. 또한 procstruct, make-struct-field-accessor, make-struct-field-mutator가 만든 접근자나 설정자라면, 결과 프로시저도 (첫) 인자 타입이 잘못되었을 때 name을 사용해요. 하지만 보통은 프로시저 이름이 내부 검사에 하드와이어되어 있으므로 name이 오류 보고에 사용되지 않아요.

package base 8.4.0.2에서 변경: realm 인자 추가.

procedure

(procedure-realm proc) → symbol?
  proc : procedure?

프로시저의 realm을 보고해요. realm은 프로시저가 만들어진 모듈, 프로시저 코드가 컴파일될 때의 current-compile-realm 값, 또는 procedure-rename 같은 함수로 명시적으로 배정된 realm에 따라 달라질 수 있어요.

package base 8.4.0.2에서 추가.

procedure

(procedure->method proc) → procedure?
  proc : procedure?

proc과 같지만, 잘못된 인자 수로 적용될 때 결과 오류가 첫 인자를 숨긴다는 점이 다른 프로시저를 반환해요. 마치 프로시저가 'method-arity-error 문법 속성으로 컴파일된 것처럼요.

procedure

(procedure-closure-contents-eq? proc1
                                proc2) → boolean?
  proc1 : procedure?
  proc2 : procedure?

proc1proc2의 클로저 내용을, 클로저 원소들을 eq?로 점별(pointwise) 비교해 같음을 비교해요.

4.20.1 키워드와 인자 개수 (Keywords and Arity)

procedure

(keyword-apply proc
               kw-lst
               kw-val-lst
               v ...
               lst
               #:<kw> kw-arg ...) → any
  proc : procedure?
  kw-lst : (listof keyword?)
  kw-val-lst : list?
  v : any/c
  lst : list?
  kw-arg : any/c

Racket 가이드의 "apply 함수" 절에서 keyword-apply를 소개해요.

apply와 같지만, kw-lstkw-val-lstv들과 lst의 위치 기반 인자에 더해 키워드 기반 인자를 제공하고, #:<kw> kw-arg 수열에 직접 제공된 키워드 인자에도 더해지며, 여기서 #:<kw>는 임의의 키워드를 나타내요.

주어진 kw-lstkeyword<?로 정렬되어야 해요. 어떤 키워드도 kw-lst에 두 번 나타나거나 kw-lst#:<kw> 양쪽에 나타날 수 없어요. 그렇지 않으면 exn:fail:contract 예외가 발생해요. 주어진 kw-val-lstkw-lst와 길이가 같아야 해요. 그렇지 않으면 exn:fail:contract 예외가 발생해요. 주어진 prockw-lst의 모든 키워드에 #:<kw>들을 더한 것을 받아야 하고, 다른 키워드를 요구하면 안 되며, v들과 lst로 제공된 만큼의 위치 기반 인자를 받아야 해요. 그렇지 않으면 exn:fail:contract 예외가 발생해요.

예시:

(define (f x #:y y #:z [z 10])
  (list x y z))
> (keyword-apply f '(#:y) '(2) '(1))
'(1 2 10)
> (keyword-apply f '(#:y #:z) '(2 3) '(1))
'(1 2 3)
> (keyword-apply f #:z 7 '(#:y) '(2) '(1))
'(1 2 7)

procedure

(procedure-arity proc) → normalized-arity?
  proc : procedure?

proc이 받아들이는 위치 기반 인자 개수에 대한 정보를 반환해요. procedure-arity?, normalized-arity?, procedure-arity-mask도 함께 보세요.

procedure

(procedure-arity? v) → boolean?
  v : any/c

유효한 arity a는 다음 중 하나예요.

  • 정확한(exact) 음이 아닌 정수. 프로시저가 정확히 a개 인자만 받는다는 뜻이에요.
  • arity-at-least 인스턴스. 프로시저가 (arity-at-least-value a)개 이상의 인자를 받는다는 뜻이에요.
  • 정수와 arity-at-least 인스턴스를 담은 리스트. 프로시저가 a의 원소 중 하나와 일치하는 임의 개수의 인자를 받을 수 있다는 뜻이에요.

procedure-arity의 결과는 항상 normalized-arity?의 의미로 정규화되어 있어요.

예시:

> (procedure-arity cons)
2
> (procedure-arity list)
(arity-at-least 0)
> (arity-at-least? (procedure-arity list))
#t
> (arity-at-least-value (procedure-arity list))
0
> (arity-at-least-value (procedure-arity (lambda (x . y) x)))
1
> (procedure-arity (case-lambda [(x) 0] [(x y) 1]))
'(1 2)

procedure

(procedure-arity-mask proc) → exact-integer?
  proc : procedure?

procedure-arity와 같은 정보를 반환하지만 다르게 인코딩해요. arity는 (bitwise-bit-set? mask n)procn개 인자를 받으면 참인 정확한 정수 mask로 인코딩돼요.

arity의 mask 인코딩은 종종 테스트하고 조작하기 더 쉬우며, procedure-arity-mask는 때로는 procedure-arity보다 빠르면서 항상 적어도 그만큼은 빨라요.

package base 7.0.0.11에서 추가.

procedure

(procedure-arity-includes? proc k [kws-ok?]) → boolean?
  proc : procedure?
  k : exact-nonnegative-integer?
  kws-ok? : any/c = #f

프로시저가 위치 기반 인자 k개를 받을 수 있으면 #t를, 그렇지 않으면 #f를 반환해요. kws-ok?#f이면 proc에 필수 키워드 인자가 없을 때만 결과가 #t예요.

예시:

> (procedure-arity-includes? cons 2)
#t
> (procedure-arity-includes? display 3)
#f
> (procedure-arity-includes? (lambda (x #:y y) x) 1)
#f
> (procedure-arity-includes? (lambda (x #:y y) x) 1 #t)
#t

procedure

(procedure-reduce-arity proc
                        arity
                        [name
                         realm]) → procedure?
  proc : procedure?
  arity : procedure-arity?
  name : (or/c symbol? #f) = #f
  realm : symbol? = 'racket

proc과 같지만(object-name이 반환하는 같은 이름 포함), arity와 일치하는 인자만 받는 프로시저를 반환해요. 특히 procedure-arity를 생성된 프로시저에 적용하면 arity의 정규화된 형태와 equal?한 값을 반환해요.

arity 명세가 (procedure-arity proc)에 없는 인자를 허용하면 exn:fail:contract 예외가 발생해요. proc이 키워드 인자를 받으면, 키워드 인자가 전부 선택적이어야 하거나(그리고 arity-감소 프로시저가 받지 않아야 하거나) arity가 빈 리스트여야 해요(호출할 수 없는 프로시저를 만듦). 그렇지 않으면 exn:fail:contract 예외가 발생해요.

name#f가 아니면 결과 프로시저의 object-namename을 만들고, 결과의 procedure-realmrealm을 만들어요. 그렇지 않으면 결과 프로시저의 object-nameprocedure-realmproc과 같은 결과를 만들어요.

예시:

> (define my+ (procedure-reduce-arity + 2))
> (my+ 1 2)
3
> (my+ 1 2 3)
+: arity mismatch;
the expected number of arguments does not match the given
number
expected: 2
given: 3
> (define also-my+ (procedure-reduce-arity + 2 'also-my+))
> (also-my+ 1 2 3)
also-my+: arity mismatch;
the expected number of arguments does not match the given
number
expected: 2
given: 3

package base 7.0.0.11에서 변경: 선택적 name 인자 추가. 8.4.0.2에서 변경: realm 인자 추가.

procedure

(procedure-reduce-arity-mask proc
                             mask
                             [name
                              realm]) → procedure?
  proc : procedure?
  mask : exact-integer?
  name : (or/c symbol? #f) = #f
  realm : symbol? = 'racket

procedure-reduce-arity와 같지만, procedure-arity-mask에 설명된 arity 표현을 사용해요.

arity의 mask 인코딩은 종종 테스트하고 조작하기 더 쉬우며, procedure-reduce-arity-mask는 때로는 procedure-reduce-arity보다 빠르면서 항상 적어도 그만큼은 빨라요.

package base 7.0.0.11에서 추가. 8.4.0.2에서 변경: realm 인자 추가.

procedure

(procedure-keywords proc) → (listof keyword?)
                             (or/c (listof keyword?) #f)
  proc : procedure?

프로시저가 요구하고 받아들이는 키워드 인자에 대한 정보를 반환해요. 첫 결과는 proc을 적용할 때 필수인 서로 다른 키워드(keyword<?로 정렬)의 리스트예요. 두 번째 결과는 받아들여지는 서로 다른 키워드(keyword<?로 정렬)의 리스트이거나, 아무 키워드나 받는다는 뜻의 #f예요. 두 번째 결과가 리스트이면 첫 리스트의 모든 원소가 두 번째 리스트에도 있어요.

예시:

> (procedure-keywords +)
'()
'()
> (procedure-keywords (lambda (#:tag t #:mode m) t))
'(#:mode #:tag)
> (procedure-keywords (lambda (#:tag t #:mode [m #f]) t))
'(#:tag)
'(#:mode #:tag)

procedure

(procedure-result-arity proc) → (or/c #f procedure-arity?)
  proc : procedure?

프로시저 proc 결과의 arity를 반환하거나, 결과 수를 알 수 없으면 #f를 반환해요. 이는 procedure-result-arity 구현의 부족이나 proc의 동작이 충분히 단순하지 않기 때문일 수 있어요.

예시:

> (procedure-result-arity
   (λ (x)
     (apply
      values
      (let loop ()
        (cond
         [(zero? (random 10)) '()]
         [else (cons 1 (loop))])))))
#f

package base 6.4.0.3에서 추가.

procedure

(make-keyword-procedure proc [plain-proc]) → procedure?
  proc : ((listof keyword?) list? any/c ... . -> . any)
  plain-proc : procedure?
             = (lambda args (apply proc null null args))

모든 키워드 인자를 받는(키워드 인자를 요구하지는 않는) 프로시저를 반환해요.

make-keyword-procedure가 반환한 프로시저가 키워드 인자와 함께 호출되면 proc이 호출돼요. 첫 인자는 keyword<?로 정렬된 서로 다른 키워드의 리스트, 두 번째 인자는 각 키워드에 대한 값을 담은 병렬 리스트, 나머지 인자는 위치 기반 인자예요.

make-keyword-procedure가 반환한 프로시저가 키워드 인자 없이 호출되면 plain-proc이 호출돼요—proc을 통한 디스패치보다 더 효율적일 수 있어요. 보통 plain-procproc을 처음 두 인자를 빈 리스트로 하고 호출한 것과 같은 동작을 해야 하지만, 그 대응 관계는 어떤 식으로도 강제되지 않아요.

새 프로시저에 대한 procedure-arityobject-name의 결과는, plain-proc이 제공되면 plain-proc과 같아요. 그렇지 않으면 object-name의 결과는 proc과 같지만, procedure-arity의 결과는 proc의 arity에서 2를 뺀(즉 키워드 인자를 다루는 두 접두 인자 없이) 것으로 파생돼요. procedure-reduce-keyword-arityprocedure-rename도 함께 보세요.

예시:

(define show
  (make-keyword-procedure (lambda (kws kw-args . rest)
                            (list kws kw-args rest))))
> (show 1)
'(() () (1))
> (show #:init 0 1 2 3 #:extra 4)
'((#:extra #:init) (4 0) (1 2 3))
(define show2
  (make-keyword-procedure (lambda (kws kw-args . rest)
                            (list kws kw-args rest))
                          (lambda args
                            (list->vector args))))
> (show2 1)
'#(1)
> (show2 #:init 0 1 2 3 #:extra 4)
'((#:extra #:init) (4 0) (1 2 3))

procedure

(procedure-reduce-keyword-arity proc
                                arity
                                required-kws
                                allowed-kws
                                [name
                                 realm]) → procedure?
  proc : procedure?
  arity : procedure-arity?
  required-kws : (listof keyword?)
  allowed-kws :
    (or/c (listof keyword?)
          #f)
  name : (or/c symbol? #f) = #f
  realm : symbol? = 'racket

procedure-reduce-arity와 같지만 required-kwsallowed-kws에 따라 키워드 인자를 제약해요. required-kwsallowed-kwskeyword<?로 정렬되어야 하고 중복이 없어야 해요. allowed-kws#f이면 결과 프로시저는 여전히 아무 키워드나 받고, 그렇지 않으면 required-kws의 키워드는 allowed-kws의 부분집합이어야 해요. 원래 procrequired-kws에 나열된 것보다 많은 키워드를 요구해서는 안 되고, allowed-kws의 키워드는 적어도 허용해야 해요(allowed-kws#f이면 모든 키워드를 허용해야 해요).

예시:

(define orig-show
  (make-keyword-procedure (lambda (kws kw-args . rest)
                            (list kws kw-args rest))))
(define show (procedure-reduce-keyword-arity
              orig-show 3 '(#:init) '(#:extra #:init)))
> (show #:init 0 1 2 3 #:extra 4)
'((#:extra #:init) (4 0) (1 2 3))
> (show 1)
arity mismatch;
the expected number of arguments does not match the given
number
  expected: 3 plus an argument with keyword #:init plus an
    optional argument with keyword #:extra
  given: 1
  arguments...:
    1
> (show #:init 0 1 2 3 #:extra 4 #:more 7)
application: procedure does not expect an argument with
given keyword
  procedure: #<procedure>
  given keyword: #:more
  arguments...:
    1
    2
    3
    #:extra 4
    #:init 0
    #:more 7

package base 8.4.0.2에서 변경: realm 인자 추가.

procedure

(procedure-reduce-keyword-arity-mask proc
                                     mask
                                     required-kws
                                     allowed-kws
                                     [name
                                      realm]) → procedure?
  proc : procedure?
  mask : exact-integer?
  required-kws : (listof keyword?)
  allowed-kws :
    (or/c (listof keyword?)
          #f)
  name : (or/c symbol? #f) = #f
  realm : symbol? = 'racket

procedure-reduce-keyword-arity와 같지만, procedure-arity-mask에 설명된 arity 표현을 사용해요.

package base 7.0.0.11에서 추가. 8.4.0.2에서 변경: realm 인자 추가.

struct

(struct arity-at-least (value)
    #:extra-constructor-name make-arity-at-least)
  value : exact-nonnegative-integer?

procedure-arity의 결과에 사용되는 구조체 타입이에요. procedure-arity?도 함께 보세요.

value

prop:procedure : struct-type-property?

인스턴스가 프로시저로 적용될 수 있는 구조체 타입을 식별하는 구조체 타입 속성이에요. 특히 인스턴스에 procedure?를 적용하면 결과가 #t이고, 적용 표현식의 함수 위치에 인스턴스를 사용하면 인스턴스에서 프로시저가 추출되어 프로시저 호출을 완료하는 데 사용돼요.

prop:procedure 속성 값이 정확한 음이 아닌 정수이면, 구조체 안에서 프로시저를 담아야 하는 필드를 지정해요. 그 정수는 0(포함)과 구조체 타입의 자동이 아닌 필드 수(제외, 슈퍼타입 필드는 세지 않음) 사이여야 해요. 지정된 필드는 또한 불변(immutable)으로 지정되어야 해요. 그래야 구조체 인스턴스가 만들어진 후 프로시저가 바뀔 수 없기 때문이에요. (그렇지 않으면 인스턴스의 arity와 이름이 바뀔 수 있는데, 그런 변경은 보통 프로시저에 허용되지 않아요.) 인스턴스가 적용 표현식의 프로시저로 사용될 때, 인스턴스에서 지정된 필드의 값이 프로시저 호출을 완료하는 데 사용돼요. (이 프로시저는 프로시저로 동작하는 다른 구조체일 수 있어요; 프로시저 필드의 불변성이 프로시저 그래프의 순환을 금지하므로, 프로시저 호출은 결국 구조체가 아닌 프로시저로 계속될 거예요.) 그 프로시저는 적용 표현식의 모든 인자를 받아요. 프로시저의 이름(object-name 참고), arity(procedure-arity 참고), 키워드 프로토콜(procedure-keywords 참고)도 구조체의 이름, arity, 키워드 프로토콜로 사용돼요. 지정된 필드의 값이 프로시저가 아니면 인스턴스는 (case-lambda)처럼 동작해요(즉 어떤 인자 수든 받지 않는 프로시저). procedure-extract-target도 함께 보세요.

make-struct-type에 정수 proc-spec 인자를 제공하는 것은 prop:procedure 속성으로 값을 공급하는 것과 필드를 불변으로 지정하는 것과 같아요(그래서 속성 바인딩이나 불변 지정은 중복되어 허용되지 않아요).

예시:

> (struct annotated-proc (base note)
    #:property prop:procedure
    (struct-field-index base))
> (define plus1 (annotated-proc
                 (lambda (x) (+ x 1))
                 "adds 1 to its argument"))
> (procedure? plus1)
#t
> (annotated-proc? plus1)
#t
> (plus1 10)
11
> (annotated-proc-note plus1)
"adds 1 to its argument"

prop:procedure 값이 프로시저이면, 적어도 하나의 비키워드 인자를 받아야 해요. 구조체 인스턴스가 적용 표현식에 사용되면 속성 값 프로시저가 인스턴스를 첫 인자로 호출돼요. 속성 값 프로시저의 나머지 인자는 적용 표현식의 인자(키워드 인자 포함)예요. 따라서 적용 표현식이 다섯 개의 비키워드 인자를 제공하면, 속성 값 프로시저는 여섯 개의 비키워드 인자로 호출돼요. 인스턴스의 이름(object-name 참고)과 키워드 프로토콜(procedure-keywords 참고)은 속성 값 프로시저의 영향을 받지 않지만, 인스턴스의 arity는 속성 값 프로시저의 가능한 비키워드 인자 수마다 1을 빼서 결정돼요. 속성 값 프로시저가 적어도 하나의 인자를 받을 수 없으면 인스턴스는 (case-lambda)처럼 동작해요.

make-struct-type에 프로시저 proc-spec 인자를 제공하는 것은 prop:procedure 속성으로 값을 공급하는 것과 같아요(그래서 특정 속성 바인딩은 허용되지 않아요).

예시:

> (struct fish (weight color)
    #:mutable
    #:property
    prop:procedure
    (lambda (f n)
      (let ([w (fish-weight f)])
        (set-fish-weight! f (+ n w)))))
> (define wanda (fish 12 'red))
> (fish? wanda)
#t
> (procedure? wanda)
#t
> (fish-weight wanda)
12
> (for-each wanda '(1 2 3))
> (fish-weight wanda)
18

prop:procedure 속성에 제공된 값이 정확한 음이 아닌 정수도 프로시저도 아니면 exn:fail:contract 예외가 발생해요.

procedure

(procedure-struct-type? type) → boolean?
  type : struct-type?

type이 나타내는 구조체 타입의 인스턴스가 프로시저(procedure?에 따름)이면 #t를, 그렇지 않으면 #f를 반환해요.

procedure

(procedure-extract-target proc) → (or/c #f procedure?)
  proc : procedure?

procprop:procedure 속성을 가진 구조체 타입의 인스턴스이고, 속성 값이 구조체의 필드를 가리키며, 필드 값이 프로시저이면 procedure-extract-target은 그 필드 값을 반환해요. 그렇지 않으면 결과는 #f예요.

prop:procedure 속성 값이 프로시저일 때, 그 프로시저는 procedure-extract-target이 반환하지 않아요. 그런 프로시저는 구조체 필드를 통해 접근하는 것과 다르고, 항상 프로시저로 적용된 구조체인 추가 인자 하나를 소비하기 때문이에요. 프로시저를 비공개로 유지하면 항상 적절한 첫 인자로 호출되도록 보장돼요.

value

prop:arity-string : struct-type-property?

prop:procedure 속성을 가진 구조체 타입이 잘못된 인자 수로 적용될 때 arity-불일치 오류 보고에 사용되는 구조체 타입 속성이에요. prop:arity-string 속성 값은 단일 인자(잘못 적용된 구조체)를 받아 문자열을 반환하는 프로시저여야 해요. 결과 문자열은 단어 "expects" 뒤에 사용되고, 오류 메시지에서 뒤에 실제 인자 수가 따라와요.

Arity-불일치 보고는 prop:arity-string 속성이 프로시저 구조체 타입과 연결되지 않았을 때 자동으로 procedure-extract-target을 사용해요.

예시:

> (struct evens (proc)
    #:property prop:procedure (struct-field-index proc)
    #:property prop:arity-string
    (lambda (p)
      "an even number of arguments"))
> (define pairs
    (evens
     (case-lambda
      [() null]
      [(a b . more)
       (cons (cons a b)
             (apply pairs more))])))
> (pairs 1 2 3 4)
'((1 . 2) (3 . 4))
> (pairs 5)
arity mismatch;
the expected number of arguments does not match the given
number
  expected: an even number of arguments
  given: 1
  arguments...:
    5

value

prop:checked-procedure : struct-type-property?

checked-procedure-check-and-extract와 함께 사용되는 구조체 타입 속성으로, 컴파일러가 키워드 인자 성능을 개선할 수 있게 하는 훅이에요. 이 속성은 슈퍼타입이 없고 필드가 적어도 두 개인 구조체 타입에만 붙일 수 있어요.

procedure

(checked-procedure-check-and-extract type
                                     v
                                     proc
                                     v1
                                     v2) → any/c
  type : struct-type?
  v : any/c
  proc : (any/c any/c any/c . -> . any/c)
  v1 : any/c
  v2 : any/c

vtype의 인스턴스이면 그로부터 값을 추출해요. typeprop:checked-procedure 속성을 가져야 해요. v가 그런 인스턴스이면 v의 첫 필드를 추출해 v1v2에 적용해요. 결과가 참 값이면 결과는 v의 두 번째 필드 값이에요.

vtype의 인스턴스가 아니거나, v의 첫 필드를 v1v2에 적용한 결과가 #f이면, procv, v1, v2에 적용하고 그 결과를 checked-procedure-check-and-extract가 반환해요.

procedure

(procedure-specialize proc) → procedure?
  proc : procedure?

proc 또는 그와 동등한 것을 반환하되, 런타임 시스템에 proc 구현을 특수화하는 데 추가 시간과 메모리를 쓰라는 힌트를 제공해요.

이 힌트는 현재 proclambdacase-lambda 폼 바깥에 바인딩된 변수들을 참조하는 lambda 또는 case-lambda 폼의 값이고, proc이 이전에 적용된 적이 없을 때 사용돼요.

package base 6.3.0.10에서 추가.

4.20.2 기본(프리미티브) 반영하기 (Reflecting on Primitives)

프리미티브 프로시저는 낮은 수준 언어로 구현될 수 있는 내장 프로시저예요. racket/base의 모든 프로시저가 프리미티브는 아니지만 많은 것이 프리미티브예요. 프리미티브와 다른 프로시저의 구분은 다른 낮은 수준 코드에 유용할 수 있어요.

procedure

(primitive? v) → boolean?
  v : any/c

v가 프리미티브 프로시저이면 #t를, 그렇지 않으면 #f를 반환해요.

procedure

(primitive-closure? v) → boolean?
  v : any/c

v가 단순한 프리미티브 프로시저가 아니라 내부적으로 프리미티브 클로저로 구현되면 #t를, 그렇지 않으면 #f를 반환해요.

procedure

(primitive-result-arity prim) → procedure-arity?
  prim : primitive?

프리미티브 프로시저 prim 결과의 arity(procedure-arity가 반환하는 프로시저의 입력 arity와 대비됨)를 반환해요. 대부분의 프리미티브에서 이 프로시저는 1을 반환하는데, 대부분의 프리미티브는 적용될 때 단일 값을 반환하기 때문이에요.

4.20.3 추가 고차 함수 (Additional Higher-Order Functions)

(require racket/function) package: base

이 절에서 문서화한 바인딩은 racket/functionracket 라이브러리가 제공하지만, racket/base는 제공하지 않아요.

procedure

(identity v) → any/c
  v : any/c

v를 반환해요.

procedure

(const v) → procedure?
  v : any/c

어떤 인자(키워드 인자 포함)도 받고 v를 반환하는 프로시저를 반환해요.

예시:

> ((const 'foo))
'foo
> ((const 'foo) 1 2 3)
'foo
> ((const 'foo) 'a 'b #:c 'c)
'foo

procedure

(const* v ...) → procedure?
  v : any/c

const와 비슷하지만 v들을 반환해요.

예시:

> ((const*))
> ((const*) 1 2 3)
> ((const*) 'a 'b #:c 'c)
> ((const* 'foo))
'foo
> ((const* 'foo) 1 2 3)
'foo
> ((const* 'foo) 'a 'b #:c 'c)
'foo
> ((const* 'foo 'foo))
'foo
'foo
> ((const* 'foo 'foo) 1 2 3)
'foo
'foo
> ((const* 'foo 'foo) 'a 'b #:c 'c)
'foo
'foo

package base 8.7.0.5에서 추가.

syntax

(thunk
  body ...+)

syntax

(thunk* body ...+)

thunk 폼은 주어진 body를 평가하는 인자 없는(0항) 함수를 만들어요. thunk* 폼도 비슷하지만 결과 함수가 임의 인자(키워드 인자 포함)를 받아요.

예시:

(define th1 (thunk (define x 1) (printf "~a\n" x)))

> (th1)
1
> (th1 'x)
th1: arity mismatch;
the expected number of arguments does not match the given
number
expected: 0
given: 1
> (th1 #:y 'z)
application: procedure does not accept keyword arguments
procedure: th1
arguments...:
#:y 'z

(define th2 (thunk* (define x 1) (printf "~a\n" x)))

> (th2)
1
> (th2 'x)
1
> (th2 #:y 'z)
1

procedure

(negate proc) → procedure?
  proc : procedure?

proc과 같지만 proc의 결과의 not을 반환하는 프로시저를 반환해요.

예시:

> (filter (negate symbol?) '(1 a 2 b 3 c))
'(1 2 3)
> (map (negate =) '(1 2 3) '(1 1 1))
'(#f #t #t)

procedure

((conjoin f ...) x ...) → any
  f : procedure?
  x : any/c

각 함수 호출을 and로 결합해요. (and (f x ...) ...)와 동등해요.

예시:

(define f (conjoin exact? integer?))

> (f 1)
#t
> (f 1.0)
#f
> (f 1/2)
#f
> (f 0.5)
#f
> ((conjoin (λ (x) (values 1 2))) 0)
1
2

procedure

((disjoin f ...) x ...) → any
  f : procedure?
  x : any/c

각 함수 호출을 or로 결합해요. (or (f x ...) ...)와 동등해요.

예시:

(define f (disjoin exact? integer?))

> (f 1)
#t
> (f 1.0)
#t
> (f 1/2)
#t
> (f 0.5)
#f
> ((disjoin (λ (x) (values 1 2))) 0)
1
2

procedure

(curry proc) → procedure?
  proc : procedure?
(curry proc v ...+) → any
  proc : procedure?
  v : any/c

(curry proc)의 결과는 proc의 커리(curried) 버전인 프로시저예요. 결과 프로시저가 처음 적용될 때, (procedure-arity proc)에 따라 받을 수 있는 최대 인자 수가 주어지지 않으면 결과는 추가 인자를 받을 프로시저예요.

예시:

> ((curry list) 1 2)
#<procedure:curried:list>
> ((curry cons) 1)
#<procedure:curried:cons>
> ((curry cons) 1 2)
'(1 . 2)

(curry proc) 결과의 첫 적용 후, 각 추가 적용은 (procedure-arity proc)에 따른 수용 가능한 인자 수가 누적될 때까지 인자를 누적하며, 그 시점에 원래 proc이 호출돼요.

예시:

> (((curry list) 1 2) 3)
'(1 2 3)
> (((curry list) 1) 3)
'(1 3)
> ((((curry foldl) +) 0) '(1 2 3))
6
> (define foo (curry (lambda (x y z) (list x y z))))
> (foo 1 2 3)
'(1 2 3)
> (((((foo) 1) 2)) 3)
'(1 2 3)

함수 호출 (curry proc v ...)((curry proc) v ...)와 동등해요. 다시 말해 curry 자체도 커리되어 있어요.

예시:

> (map ((curry +) 10) '(1 2 3))
'(11 12 13)
> (map (curry + 10) '(1 2 3))
'(11 12 13)
> (map (compose (curry * 2) (curry + 10)) '(1 2 3))
'(22 24 26)

curry 함수는 키워드 인자를 가진 함수도 지원해요: (procedure-keywords proc)에 따른 모든 필수 키워드 인자가 제공될 때까지 키워드 인자가 위치 인자와 같은 방식으로 누적돼요.

예시:

(define (f #:a a #:b b #:c c)
  (list a b c))
> ((((curry f) #:a 1) #:b 2) #:c 3)
'(1 2 3)
> ((((curry f) #:b 1) #:c 2) #:a 3)
'(3 1 2)
> ((curry f #:a 1 #:c 2) #:b 3)
'(1 3 2)

package base 7.0.0.7에서 변경: 키워드 인자 지원 추가.

procedure

(curryr proc) → procedure?
  proc : procedure?
(curryr proc v ...+) → any
  proc : procedure?
  v : any/c

curry와 같지만, 인자가 반대 방향으로 수집돼요: 첫 단계가 가장 오른쪽 인자 묶음을 수집하고, 다음 단계들이 이들의 왼쪽에 인자를 추가해요.

예시:

> (map (curryr list 'foo) '(1 2 3))
'((1 foo) (2 foo) (3 foo))

procedure

(normalized-arity? arity) → boolean?
  arity : any/c

정규화된 arity는 다음 형태 중 하나예요.

  • 빈 리스트;
  • 정확한 음이 아닌 정수;
  • arity-at-least 인스턴스;
  • 둘 이상의 엄격히 증가하는 정확한 음이 아닌 정수 리스트; 또는
  • 하나 이상의 엄격히 증가하는 정확한 음이 아닌 정수 리스트 뒤에, 앞의 정수보다 적어도 2만큼 큰 값의 단일 arity-at-least 인스턴스.

모든 정규화된 arity는 유효한 프로시저 arity이며 procedure-arity?를 만족해요. arity=?인 임의의 두 정규화된 arity 값도 equal?이어야 해요.

예시:

> (normalized-arity? (arity-at-least 1))
#t
> (normalized-arity? (list (arity-at-least 1)))
#f
> (normalized-arity? (list 0 (arity-at-least 2)))
#t
> (normalized-arity? (list (arity-at-least 2) 0))
#f
> (normalized-arity? (list 0 2 (arity-at-least 3)))
#f

procedure

(normalize-arity arity) → (and/c normalized-arity? (lambda (x) (arity=? x arity)))
  arity : procedure-arity?

arity의 정규화된 형태를 만들어 내요. normalized-arity?arity=?도 함께 보세요.

예시:

> (normalize-arity 1)
1
> (normalize-arity (list 1))
1
> (normalize-arity (arity-at-least 2))
(arity-at-least 2)
> (normalize-arity (list (arity-at-least 2)))
(arity-at-least 2)
> (normalize-arity (list 1 (arity-at-least 2)))
(arity-at-least 1)
> (normalize-arity (list (arity-at-least 2) 1))
(arity-at-least 1)
> (normalize-arity (list (arity-at-least 2) 3))
(arity-at-least 2)
> (normalize-arity (list 3 (arity-at-least 2)))
(arity-at-least 2)
> (normalize-arity (list (arity-at-least 6) 0 2 (arity-at-least 4)))
(list 0 2 (arity-at-least 4))

procedure

(arity=? a b) → boolean?
  a : procedure-arity?
  b : procedure-arity?

arity ab를 가진 프로시저가 같은 수의 인자를 받으면 #true를, 그렇지 않으면 #false를 반환해요. (and (arity-includes? a b) (arity-includes? b a))(equal? (normalize-arity a) (normalize-arity b)) 둘 다와 동등해요.

예시:

> (arity=? 1 1)
#t
> (arity=? (list 1) 1)
#t
> (arity=? 1 (list 1))
#t
> (arity=? 1 (arity-at-least 1))
#f
> (arity=? (arity-at-least 1) 1)
#f
> (arity=? (arity-at-least 1) (list 1 (arity-at-least 2)))
#t
> (arity=? (list 1 (arity-at-least 2)) (arity-at-least 1))
#t
> (arity=? (arity-at-least 1) (list 1 (arity-at-least 3)))
#f
> (arity=? (list 1 (arity-at-least 3)) (arity-at-least 1))
#f
> (arity=? (list 0 1 2 (arity-at-least 3)) (list (arity-at-least 0)))
#t
> (arity=? (list (arity-at-least 0)) (list 0 1 2 (arity-at-least 3)))
#t
> (arity=? (list 0 2 (arity-at-least 3)) (list (arity-at-least 0)))
#f
> (arity=? (list (arity-at-least 0)) (list 0 2 (arity-at-least 3)))
#f

procedure

(arity-includes? a b) → boolean?
  a : procedure-arity?
  b : procedure-arity?

arity a를 가진 프로시저가 arity b를 가진 프로시저가 받는 임의의 인자 수를 받으면 #true를 반환해요.

예시:

> (arity-includes? 1 1)
#t
> (arity-includes? (list 1) 1)
#t
> (arity-includes? 1 (list 1))
#t
> (arity-includes? 1 (arity-at-least 1))
#f
> (arity-includes? (arity-at-least 1) 1)
#t
> (arity-includes? (arity-at-least 1) (list 1 (arity-at-least 2)))
#t
> (arity-includes? (list 1 (arity-at-least 2)) (arity-at-least 1))
#t
> (arity-includes? (arity-at-least 1) (list 1 (arity-at-least 3)))
#t
> (arity-includes? (list 1 (arity-at-least 3)) (arity-at-least 1))
#f
> (arity-includes? (list 0 1 2 (arity-at-least 3)) (list (arity-at-least 0)))
#t
> (arity-includes? (list (arity-at-least 0)) (list 0 1 2 (arity-at-least 3)))
#t
> (arity-includes? (list 0 2 (arity-at-least 3)) (list (arity-at-least 0)))
#f
> (arity-includes? (list (arity-at-least 0)) (list 0 2 (arity-at-least 3)))
#t

더 알아보기