In Javascript there is a pattern called the Russian doll pattern (this may also be called a 'one-shot'). Basically, it's a function that replaces itself with another at some point.
Simple example:
var func = function(){
func = function(){ console.log("subsequent calls call this...");};
console.log("first call");
}
So the first time you call func it'll output "first call" and the next (and subsequent times) it's print "subsequent calls call this...". (this would be easy to do in Scheme as well, for example)
I've been puzzling on how to do this in Ocaml?
Edit: one solution I've come up with:
let rec func = ref( fun () -> func := ( fun () -> Printf.printf("subsequent..\n"));Printf.printf("First..\n"));;
Called as: !func () ;;
Interestingly, if I do not include the 'rec' in the definition, it never calls the subsequent function... It always prints 'First...'.
yzzlr answer is very good, but two remarks:
It forces the input of the functions to be of type unit. You can use a polymorphic version:
let doll f1 f2 =
let rec f = ref (fun x -> f := f2; f1 x) in
(fun x -> !f x);;
You can do without the hairy recursion:
let doll f1 f2 =
let f = ref f1 in
f := (fun x -> f := f2; f1 x);
(fun x -> !f x);;
(Replacing recursion with mutation is a common trick; it can actually be used to define fixpoints without using "rec")
It's pretty straightforward, but you need to use side-effects. Here's a function that takes two thunks as arguments, and returns a new thunk that calls the first thunk the first time, and the second thunk every other time.
let doll f1 f2 =
let f = ref f1 in
(fun () ->
let g = !f in
f := f2;
g ())
This isn't quite optimal, because we'll keep on overwriting the ref with the same value over and over.
Here's a slightly better version, which uses a recursive definition.
let doll f1 f2 =
let rec f = ref (fun () -> f := f2;f1 ()) in
(fun () -> !f ())
So, now, you'll get this:
# let f = doll (fun () -> 1) (fun () -> 2);;
val f : unit -> int = <fun>
# f ();;
- : int = 1
# f ();;
- : int = 2
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With