Как реализовать русскую кукольную модель в Окамле? - PullRequest
5 голосов
/ 20 марта 2011

В Javascript есть шаблон, называемый шаблоном русской куклы (его также можно назвать «одноразовым»). По сути, это функция, которая в какой-то момент заменяет себя другой.

Простой пример:

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

Итак, при первом вызове func он выдаст «первый вызов», а в следующий (и последующий раз) напечатает «последующие вызовы вызывают это ...». (это было бы легко сделать, например, в Схеме)

Я ломал голову над тем, как это сделать в Окамле?

Редактировать: одно решение, которое я придумал:

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

Называется как: ! func () ;;

Интересно, что если я не включу 'rec' в определение, он никогда не вызовет последующую функцию ... Он всегда печатает 'First ...'.

Ответы [ 2 ]

10 голосов
/ 21 марта 2011

yzzlr ответ очень хороший, но два замечания:

Это заставляет ввод функций иметь тип единицы.Вы можете использовать полиморфную версию:

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

Вы можете обойтись без волосатой рекурсии:

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

(Замена рекурсии мутацией - обычная уловка; ее можно использовать для определенияточки привязки без использования "rec")

9 голосов
/ 20 марта 2011

Это довольно просто, но вам нужно использовать побочные эффекты. Вот функция, которая принимает два thunk в качестве аргументов и возвращает новый thunk, который вызывает первый thunk в первый раз, а второй thunk через раз.

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

Это не совсем оптимально, потому что мы будем перезаписывать ссылку с одним и тем же значением снова и снова.

Вот немного лучшая версия, в которой используется рекурсивное определение.

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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...