在Javascript中有一种称为俄罗斯娃娃图案的图案(这也可称为“一次拍摄”)。基本上,它是一个在某个时刻取代另一个的功能。
简单示例:
var func = function(){
func = function(){ console.log("subsequent calls call this...");};
console.log("first call");
}
因此,当您第一次调用func时,它将输出“first call”,然后下一个(以及随后的时间)打印“后续调用调用此...”。 (例如,这在Scheme中很容易做到)
我一直在困惑如何在Ocaml中做到这一点?
编辑:我提出的一个解决方案:
let rec func = ref( fun () -> func := ( fun () -> Printf.printf("subsequent..\n"));Printf.printf("First..\n"));;
被称为: !func();;
有趣的是,如果我没有在定义中包含'rec',它就不会调用后续函数......它总是打印'First ...'。
答案 0 :(得分:10)
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”)
答案 1 :(得分:9)
这很简单,但你需要使用副作用。这是一个以两个thunk作为参数的函数,并返回一个新的thunk,它第一次调用第一个thunk,第二个thunk每隔一次。
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