gpt4 book ai didi

types - 如何在 OCaml 中实现协变可观察

转载 作者:行者123 更新时间:2023-12-02 01:53:47 26 4
gpt4 key购买 nike

我正在尝试为值制作一个包装器,允许调用者自行注册以获取有关它的通知。这是一些(工作)代码:

module Thing :
sig
type +'a t
val make : 'a -> 'a t
val watch : ('a -> unit) -> 'a t -> unit
val notify : 'a t -> unit
end = struct
type 'a t = {
obj : 'a;
watchers : (unit -> unit) Queue.t
}

let make x = {
obj = x;
watchers = Queue.create ()
}

let watch fn x =
x.watchers |> Queue.add (fun () -> fn x.obj)

let notify x =
x.watchers |> Queue.iter (fun fn -> fn ())
end

let () =
let x = Thing.make (`Int 4) in
Thing.watch (fun (`Int d) -> Printf.printf "Observed %d\n" d) x;
let x = (x :> [`Int of int | `None] Thing.t) in
Thing.notify x

但是,这似乎效率不高。每个排队的观察者都是一个新的闭包,具有自己对事物的引用。只对用户的回调进行排队并在 notify 中添加 x 会更有意义,例如

  ... = struct
type 'a t = {
obj : 'a;
watchers : ('a -> unit) Queue.t
}

let make x = {
obj = x;
watchers = Queue.create ()
}

let watch fn x =
x.watchers |> Queue.add fn

let notify x =
x.watchers |> Queue.iter (fun fn -> fn x.obj)
end

但是将 'a 作为队列类型的一部分意味着 'a t 不再是协变的。我明白为什么会这样,但是有人有解决办法吗?即我如何向 OCaml 表明在这种情况下它是安全的?

最佳答案

你可以改变捕获的位置:

module Thing :
sig
type +'a t
val make : 'a -> 'a t
val watch : ('a -> unit) -> 'a t -> unit
val notify : 'a t -> unit
end = struct
type 'a t = {
obj : 'a;
watch : ('a -> unit) -> unit;
notify : unit -> unit;
}

let make x =
let queue = Queue.create () in
let obj = x in
let watch f = Queue.add f queue in
let notify () = Queue.iter (fun f -> f x) queue in
{ obj; watch; notify; }

let watch fn x = x.watch fn
let notify x = x.notify ()
end

如果你想感觉真的很经济:

    let make x =
let queue = Queue.create () in
let obj = x in
let rec watch f = Queue.add f queue
and notify () = Queue.iter (fun f -> f x) queue in
{ obj; watch; notify; }

关于types - 如何在 OCaml 中实现协变可观察,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21377727/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com