2011-03-20 11 views
5

Javascript'te, Rus bebek modeli adı verilen bir desen vardır (bu ayrıca 'tek çekim' olarak da adlandırılabilir). Temel olarak, bir noktada kendisini başka biriyle değiştiren bir işlevdir.Ocaml'de Rus bebek modeli nasıl uygulanır?

Basit bir örnek:

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

Yani onu fonk çıktı "ilk çağrı" ve bir sonraki (ve müteakip defa) olacak diyoruz ilk kez baskı var "sonraki aramalarda bu ara ...". (Bu, şemada da yapılması kolay olurdu, örneğin)

Bunu Ocaml'de nasıl yapacağım konusunda çok şaşırdım?

Düzenleme: olarak

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

Aranan:! Tek çözüm ben ile geldim fonksiyon() ;;

İlginçtir, eğer tanımda 'rec' içermezsem, hiçbir zaman sonraki işlevi çağırmaz ... Her zaman 'İlk' ... 'i basar.

+4

Bu ... sadece yanlıştır. – phooji

+2

, aşağıda önerilen OCaml çözümlerinin, "func" kelimesinin mutabilitesini kapsülleydiklerinden, JavaScript örneğinizin "daha temiz" olduğunu lütfen unutmayın: ilk aramadan sonra, işlev iyi için değiştirilir ve kimse onu değiştirmek için bir referansa erişemez. geri. Bu, "bebek" çağrısına yerel "f" referansı yapılarak yapılır. Tabi ki, referansın hala mevcut olması için referans olmasını isterseniz, bu mümkün olabilirdi. – gasche

cevap

9

Bu oldukça basit, ancak yan etkileri kullanmanız gerekiyor. İşte, iki thunks'i argüman olarak alan bir fonksiyon ve ilk defa ilk thunk, ikinci seferinde ise her seferinde yeni bir thunk döndürür.

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

Bu tam olarak uygun değil, çünkü ref değerini aynı değerin üzerine tekrar tekrar yazmaya devam edeceğiz.

İşte yinelemeli bir tanım kullanan biraz daha iyi bir sürümü.

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

Yani, şimdi, bunu elde edersiniz:

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

yzzlr cevabı çok iyidir, ama iki Açıklamalar:

Bu tip biriminin olması fonksiyonların girişi zorlar . aslında kullanmadan sabit nokta tanımlamak için kullanılabilir "; mutasyonu

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

(Değiştirme özyineleme ortak hile:

let doll f1 f2 = 
    let rec f = ref (fun x -> f := f2; f1 x) in 
    (fun x -> !f x);; 
Kıllı özyineleme olmadan yapabilirsiniz

: Bir polimorfik sürümünü kullanabilirsiniz rec ")