如何在 OCaml 中使协变可观察

2024-05-02

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

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

然而,这似乎效率很低。每个排队的观察者都是一个新的闭包,具有自己对该事物的引用。仅对用户的回调进行排队并添加x in notify, e.g.

  ... = 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; }
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何在 OCaml 中使协变可观察 的相关文章

  • OCaml 文字负数?

    我在学 这是我觉得奇怪的事情 let test treeways x match x with when x lt 0 gt 1 when x gt 0 gt 1 gt 0 如果我这样称呼它 test threeways 10 我会得到类型
  • Java 泛型 - 重写抽象方法并具有子类的返回类型

    我正在尝试创建一个设置 其中一组子类覆盖超类 这个超类包含一个抽象方法 理想情况下 其返回类型是调用该方法的对象的返回类型 这样它的有效行为如下 public abstract class SuperClass public abstrac
  • 将“列表”转换为“集合”?

    OCaml 真的没有从列表转换为集合的函数吗 如果是这样的话 是否可以制作一个通用函数list to set 我尝试制作一个多态集 但没有成功 基本问题 列表可以包含任何类型的元素 集合 假设你的意思是Set http caml inria
  • 二维数组的 MPI 数据类型

    我需要将一个整数数组的数组 基本上是一个二维数组 从根传递给所有处理器 我在 C 程序中使用 MPI 如何声明二维数组的 MPI 数据类型以及如何发送消息 我应该使用广播还是分散 你需要使用播送 http www netlib org ut
  • 什么时候应该使用双精度而不是十进制?

    我可以说出使用的三个优点double or float 代替decimal 使用更少的内存 速度更快 因为处理器本身支持浮点数学运算 可以表示更大范围的数字 但这些优点似乎只适用于计算密集型操作 例如建模软件中的操作 当然 当需要精度时 例
  • 如何使 PyCharm 从函数定义中获取类型提示并在文档字符串中填充类型值?

    我总是在函数定义中使用类型提示 例如 def foo a int b str gt bool pass 当我使用 PyCharm 自动文档字符串生成器在代码中生成文档字符串时 我得到以下信息 def foo a int b str gt b
  • 检查一个数字是 int 还是 float

    在perl中 我想检查给定变量是否包含浮点数 为了检查我正在使用的 my Var 0 02 Floating point number if int Var Var floating point number 但上面的代码对于 0 0 不起
  • GetType() 在 Type 实例上返回什么?

    我在一些调试过程中遇到了这段代码 private bool HasBaseType Type type out Type baseType Type originalType type GetType baseType GetBaseTyp
  • python numpy:更改 numpy 矩阵的列类型

    我有一个 numpy 矩阵 X 我尝试使用以下代码更改第 1 列的数据类型 X 1 astype str print type X 0 1 但我得到了以下结果
  • VB.NET 中的类型比较

    如何比较 VB NET 中的类型数据类型 我的代码 Private Function Equal ByVal parameter As String ByVal paramenterName As String ByVal dataType
  • 时间:2019-03-17 标签:c#datatypes->oracledatatypes

    我喜欢在 Oracle 数据库中保存不同的 C 数据类型 int decimal double string Guid 有谁有一个表显示要使用哪些 Oracle 数据类型 我找到了一些表格 显示了哪些 c 数据类型可用于不同的 oracle
  • 强制类型差异

    在 Scala 中 我可以在编译时强制执行类型相等 例如 case class Foo A B a A b B implicit ev A B scala gt Foo 1 2 res3 Foo Int Int Foo 1 2 scala
  • C++dynamic_cast vs 在静态枚举中存储对象类型?

    我正在为一个框架开发一个大的类层次结构 完成后将需要大量的类型转换 我的问题是 放入一个使用枚举来存储层次结构中所有对象类型的静态成员是多么愚蠢的想法 让每个类的成员都是静态的不会增加实例化对象的大小 并且会提供一种 可能 比dynamic
  • Scala:需要类类型,但找到了 T

    我发现了与此特定问题类似的问题 但是该问题是由于有人试图直接实例化 T 造成的 在这里 我试图创建一个特征 它是一个通用接口来扩展类并将它们自动存储在数据库中 例如 Riak 使用classOf T 使用 Scala 2 10 这是我的代码
  • 为什么在 OCaml 中更喜欢柯里化而不是元组参数?

    Caml简介 http www cs jhu edu scott pl lectures caml intro html says 请注意 在 Caml 中 最好对多参数函数使用柯里化函数定义 而不是元组 比较时 a gt b gt c调用
  • 如何使用 Frama-c Value 插件的 Value.Eval_expr、Value.Eval_op 等模块中的函数

    我正在尝试创建一个 frama c 插件 该插件依赖于 Frama c Value 插件 我想获取并打印 C 源代码中所有左值的值集 为了做到这一点 我想使用 Value Eval exprs Value Eval op 等中可用的函数 例
  • Python 类型安全吗?

    根据维基百科 https en wikipedia org wiki Type system Type safety and memory safety 如果一种语言不允许违反类型系统规则的操作或转换 计算机科学家就认为该语言是 类型安全的
  • 在 C++ 中,当我将值传递给函数时,它是否总是转换为适当的类型?

    如果我有一个像这样的函数void func size t x 我称该函数为func 5 5 立即转换为size t类型 这通常适用于所有类型吗 我问这个问题是因为我发誓我见过人们编写代码 他们做类似的事情func 5 0 将 5 作为双精度
  • C# 中值类型和引用类型有什么区别? [复制]

    这个问题在这里已经有答案了 我知道一些差异 值类型存储在堆栈上 而引用类型存储在托管堆上 值类型变量直接包含它们的值 而引用变量仅包含对托管堆上创建的对象位置的引用 我错过了任何其他区别吗 如果是的话 它们是什么 请阅读 堆栈是一个实现细节
  • 在 Elasticsearch php API 中使用多种类型或索引

    我想使用查询多种类型和索引Elasticsearch PHP API 但我不知道怎么办 我应该将类型和索引的数组传递给 params params index index array of indices params type types

随机推荐