나는 최근에 다른 개념들 중에서도 클로저가 제시된 프로그래밍 언어에 관한 온라인 과정에 참석했다. 저는이 과정에서 영감을 얻은 두 가지 예를 작성하여 질문을하기 전에 약간의 맥락을 제시합니다.
첫 번째 예는 1에서 x까지의 숫자 목록을 생성하는 SML 함수입니다. 여기서 x는 함수의 매개 변수입니다.
fun countup_from1 (x: int) =
let
fun count (from: int) =
if from = x
then from :: []
else from :: count (from + 1)
in
count 1
end
SML REPL에서 :
val countup_from1 = fn : int -> int list
- countup_from1 5;
val it = [1,2,3,4,5] : int list
이 countup_from1
함수는 컨텍스트 count
에서 변수를 캡처하고 사용하는 도우미 클로저 를 사용합니다 x
.
두 번째 예에서 함수를 호출하면 create_multiplier t
인수에 t를 곱하는 함수 (실제로 클로저)가 다시 나타납니다.
fun create_multiplier t = fn x => x * t
SML REPL에서 :
- fun create_multiplier t = fn x => x * t;
val create_multiplier = fn : int -> int -> int
- val m = create_multiplier 10;
val m = fn : int -> int
- m 4;
val it = 40 : int
- m 2;
val it = 20 : int
그래서 변수 m
는 함수 호출에 의해 반환 된 클로저에 바인딩되어 있으며 이제는 마음대로 사용할 수 있습니다.
이제 클로저가 평생 동안 올바르게 작동하려면 캡처 된 변수의 수명을 연장해야합니다 t
(예 : 정수이지만 모든 유형의 값이 될 수 있음). 내가 아는 한, SML에서 이것은 가비지 콜렉션에 의해 가능합니다. 클로저는 캡처 된 값에 대한 참조를 유지합니다. 캡처 된 값은 나중에 클로저가 파괴 될 때 가비지 콜렉터에 의해 폐기됩니다.
내 질문 : 일반적으로 가비지 수집은 클로저가 안전하다는 것을 보장하는 유일한 메커니즘 (전체 수명 동안 호출 가능)입니까?
또는 가비지 수집없이 클로저의 유효성을 보장 할 수있는 다른 메커니즘은 무엇입니까? 캡처 된 값을 복사하여 클로저에 저장합니까? 캡처 된 변수가 만료 된 후에 호출 할 수 없도록 클로저 자체의 수명을 제한합니까?
가장 많이 사용되는 방법은 무엇입니까?
편집하다
캡처 된 변수를 클로저에 복사하여 위의 예를 설명 / 구현할 수 있다고 생각하지 않습니다. 일반적으로 캡처 된 변수는 모든 유형이 될 수 있습니다. 예를 들어 변수는 매우 큰 (불변) 목록에 바인딩 될 수 있습니다. 따라서 구현시 이러한 값을 복사하는 것은 매우 비효율적입니다.
완성도를 높이기 위해 다음은 참조 및 부작용을 사용하는 또 다른 예입니다.
(* Returns a closure containing a counter that is initialized
to 0 and is incremented by 1 each time the closure is invoked. *)
fun create_counter () =
let
(* Create a reference to an integer: allocate the integer
and let the variable c point to it. *)
val c = ref 0
in
fn () => (c := !c + 1; !c)
end
(* Create a closure that contains c and increments the value
referenced by it it each time it is called. *)
val m = create_counter ();
SML REPL에서 :
val create_counter = fn : unit -> unit -> int
val m = fn : unit -> int
- m ();
val it = 1 : int
- m ();
val it = 2 : int
- m ();
val it = 3 : int
따라서 변수는 참조로 캡처 할 수 있으며이를 생성 한 함수 호출 create_counter ()
이 완료된 후에도 여전히 유효합니다 .