在Javascript中有一种称为俄罗斯娃娃模式的模式(这也可称为"一次性").基本上,它是一个在某些时候取代另一个的功能.
简单的例子:
var func = function(){
func = function(){ console.log("subsequent calls call this...");};
console.log("first call");
}
Run Code Online (Sandbox Code Playgroud)
因此,第一次调用func时它将输出"first call",然后下一个(以及随后的时间)打印"后续调用调用此...".(这在Scheme中很容易做到,例如)
我一直在困惑如何在Ocaml中做到这一点?
编辑:我提出的一个解决方案:
let rec func = ref( fun () -> func := ( fun () -> Printf.printf("subsequent..\n"));Printf.printf("First..\n"));;
Run Code Online (Sandbox Code Playgroud)
被称为:!func();;
有趣的是,如果我没有在定义中包含'rec',它从不调用后续函数......它总是打印'First ...'.
gas*_*che 10
yzzlr答案非常好,但有两个评论:
它强制函数的输入为单位类型.您可以使用多态版本:
let doll f1 f2 =
let rec f = ref (fun x -> f := f2; f1 x) in
(fun x -> !f x);;
Run Code Online (Sandbox Code Playgroud)
你可以不用毛茸茸的递归:
let doll f1 f2 =
let f = ref f1 in
f := (fun x -> f := f2; f1 x);
(fun x -> !f x);;
Run Code Online (Sandbox Code Playgroud)
(用变异替换递归是一种常见的技巧;它实际上可以用来定义固定点而不使用"rec")
这很简单,但你需要使用副作用.这是一个以两个thunk作为参数的函数,并返回一个新的thunk,它第一次调用第一个thunk,每隔一个时间调用第二个thunk.
let doll f1 f2 =
let f = ref f1 in
(fun () ->
let g = !f in
f := f2;
g ())
Run Code Online (Sandbox Code Playgroud)
这不是最佳选择,因为我们将一遍又一遍地使用相同的值继续覆盖ref.
这是一个稍微好一点的版本,它使用递归定义.
let doll f1 f2 =
let rec f = ref (fun () -> f := f2;f1 ()) in
(fun () -> !f ())
Run Code Online (Sandbox Code Playgroud)
所以,现在,你会得到这个:
# let f = doll (fun () -> 1) (fun () -> 2);;
val f : unit -> int = <fun>
# f ();;
- : int = 1
# f ();;
- : int = 2
Run Code Online (Sandbox Code Playgroud)