프로시저
프로시저 (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>는 임의의 키워드를 나타내요.
주어진 proc은 v 개수에 lst의 길이를 더한 만큼의 인자를 받아야 하고, 제공된 키워드 인자를 받아야 하며, 다른 키워드 인자를 요구해서는 안 돼요. 그렇지 않으면 exn:fail:contract 예외가 발생해요. 주어진 proc은 apply 호출에 대해 꼬리 위치에서 호출돼요.
예시:
> (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인 프로시저를 반환해요.
주어진 name과 realm은 결과 프로시저가 잘못된 인자 수로 적용될 때 출력 및 오류 메시지 조정에 사용돼요. 또한 proc이 struct, 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?
proc1과 proc2의 클로저 내용을, 클로저 원소들을 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-lst와 kw-val-lst가 v들과 lst의 위치 기반 인자에 더해 키워드 기반 인자를 제공하고, #:<kw> kw-arg 수열에 직접 제공된 키워드 인자에도 더해지며, 여기서 #:<kw>는 임의의 키워드를 나타내요.
주어진 kw-lst는 keyword<?로 정렬되어야 해요. 어떤 키워드도 kw-lst에 두 번 나타나거나 kw-lst와 #:<kw> 양쪽에 나타날 수 없어요. 그렇지 않으면 exn:fail:contract 예외가 발생해요. 주어진 kw-val-lst는 kw-lst와 길이가 같아야 해요. 그렇지 않으면 exn:fail:contract 예외가 발생해요. 주어진 proc은 kw-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)이 proc이 n개 인자를 받으면 참인 정확한 정수 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-name은 name을 만들고, 결과의 procedure-realm은 realm을 만들어요. 그렇지 않으면 결과 프로시저의 object-name과 procedure-realm은 proc과 같은 결과를 만들어요.
예시:
> (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-proc은 proc을 처음 두 인자를 빈 리스트로 하고 호출한 것과 같은 동작을 해야 하지만, 그 대응 관계는 어떤 식으로도 강제되지 않아요.
새 프로시저에 대한 procedure-arity와 object-name의 결과는, plain-proc이 제공되면 plain-proc과 같아요. 그렇지 않으면 object-name의 결과는 proc과 같지만, procedure-arity의 결과는 proc의 arity에서 2를 뺀(즉 키워드 인자를 다루는 두 접두 인자 없이) 것으로 파생돼요. procedure-reduce-keyword-arity와 procedure-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-kws와 allowed-kws에 따라 키워드 인자를 제약해요. required-kws와 allowed-kws는 keyword<?로 정렬되어야 하고 중복이 없어야 해요. allowed-kws가 #f이면 결과 프로시저는 여전히 아무 키워드나 받고, 그렇지 않으면 required-kws의 키워드는 allowed-kws의 부분집합이어야 해요. 원래 proc은 required-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?
proc이 prop: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
v가 type의 인스턴스이면 그로부터 값을 추출해요. type은 prop:checked-procedure 속성을 가져야 해요. v가 그런 인스턴스이면 v의 첫 필드를 추출해 v1과 v2에 적용해요. 결과가 참 값이면 결과는 v의 두 번째 필드 값이에요.
v가 type의 인스턴스가 아니거나, v의 첫 필드를 v1과 v2에 적용한 결과가 #f이면, proc을 v, v1, v2에 적용하고 그 결과를 checked-procedure-check-and-extract가 반환해요.
procedure
(procedure-specialize proc) → procedure?
proc : procedure?
proc 또는 그와 동등한 것을 반환하되, 런타임 시스템에 proc 구현을 특수화하는 데 추가 시간과 메모리를 쓰라는 힌트를 제공해요.
이 힌트는 현재 proc이 lambda나 case-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/function과 racket 라이브러리가 제공하지만, 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 a와 b를 가진 프로시저가 같은 수의 인자를 받으면 #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