2011-03-20 5 views
5

자바 스크립트에는 러시아 인형 패턴이라는 패턴이 있습니다 (이 패턴을 '원샷'이라고도 함). 기본적으로, 그것은 어떤 시점에서 다른 것으로 대체되는 함수입니다.Ocaml에서 러시아어 인형 패턴을 구현하는 방법은 무엇입니까?

간단한 예 :

var func = function(){ 
    func = function(){ console.log("subsequent calls call this...");}; 
    console.log("first call"); 
} 

그래서 당신이 그것을 FUNC 출력 "첫 번째 전화"와 다음 (이후 회) 거를 호출 처음은 인쇄의 "후속 호출이 전화를 ...". (이것은 Scheme에서도 쉽게 할 수 있습니다.)

저는 Ocaml에서 이것을하는 방법에 대해 의아해했습니다.

편집 :로

let rec func = ref(fun() -> func := (fun() -> Printf.printf("subsequent..\n"));Printf.printf("First..\n"));; 

호출 :! 하나 개의 솔루션은 내가 함께 왔어요 FUNC();

흥미롭게도 'rec'를 정의에 포함시키지 않으면 연속 함수를 호출하지 않습니다. 항상 'First ...'를 인쇄합니다.

+4

그건 ... 그냥 잘못되었습니다. – phooji

+2

아래에 제안 된 OCaml 솔루션은 JavaScript 예제에서 "func"의 변경 가능성을 캡슐화하기 때문에 "깨끗합니다"라는 점에 유의하십시오. 첫 번째 호출 후에 기능이 좋게 변경되고 아무도 변경 사항을 참조로 액세스 할 수 없습니다 뒤로. 이 작업은 "인형"호출에 대해 "f"참조를 사용하여 수행됩니다. 물론 수정을 위해 참조를 사용할 수 있기를 원한다면 가능할 수도 있습니다. – gasche

답변

9

매우 간단하지만 부작용을 사용해야합니다. 다음은 두 개의 썽크를 인수로 사용하여 처음에는 첫 번째 썽크를 호출하고 두 번째 틱은 두 번 호출하는 새 썽크를 반환하는 함수입니다.

let doll f1 f2 = 
    let f = ref f1 in 
    (fun() -> 
     let g = !f in 
     f := f2; 
     g()) 

ref를 동일한 값으로 반복해서 덮어 쓰고 있기 때문에 이것은 최적이 아닙니다.

다음은 재귀 적 정의를 사용하는 약간 더 나은 버전입니다.

let doll f1 f2 = 
    let rec f = ref (fun() -> f := f2;f1()) in 
    (fun() -> !f()) 

그래서, 지금, 당신이 얻을 것이다 :

# let f = doll (fun() -> 1) (fun() -> 2);; 
val f : unit -> int = <fun> 
# f();; 
- : int = 1 
# f();; 
- : int = 2 
10

yzzlr의 대답은 매우 훌륭하지만이 발언 :

그것은 형 유닛 할 수있는 기능의 입력을 강제를 . 실제로 사용하지 않고 fixpoints을 정의 할 수 있습니다 "; 변이

let doll f1 f2 = 
    let f = ref f1 in 
    f := (fun x -> f := f2; f1 x); 
    (fun x -> !f x);; 

(교체 재귀 공통 트릭 :

let doll f1 f2 = 
    let rec f = ref (fun x -> f := f2; f1 x) in 
    (fun x -> !f x);; 
당신은 털이 재귀없이 할 수

: 당신은 다형성 버전을 사용할 수 있습니다 rec ")

관련 문제