【问题标题】:OCaml insist that function is not polymorphic, but don't specify the typeOCaml 坚持认为函数不是多态的,但不指定类型
【发布时间】:2018-05-22 04:57:43
【问题描述】:

是否可以显式写下非多态但延迟统一的类型,如下划线类型?

因此,OCaml 有时会在类型检查过程中生成一个顶级打印的类型,该类型带有前导下划线(例如_a)。具体来说,这些会在实例化一个空的Hashtbl.t 时以及在某些其他情况下出现。

# Hashtbl.create 1;;
- : ('_a, '_b) Hashtbl.t = <abstr>

但是,用户不能在源代码中明确引用这些类型。

# (5: int);;
- : int = 5
# (5: 'a);;
- : int = 5
# (5: '_a);;
Error: The type variable name '_a is not allowed in programs

您可以通过利用 OCaml 中缺乏高阶多态性来创建显式非多态函数

# let id = snd ((), fun y -> y);;
val id : '_a -> '_a = <fun>
# (fun () -> fun y -> y) ();;
- : '_a -> '_a = <fun>

我希望能够做类似的事情

let id : <some magical type> = fun x -> x

并且不依赖于将来可能会消失的类型系统的限制。

【问题讨论】:

  • 请问为什么你会想要这样做?
  • @AndreasRossberg,当时我正在为用 C 编写的库编写 OCaml 接口。有问题的特定项目倾向于避免使用 .mli 文件。回想起来,这不是一个好方法。

标签: ocaml


【解决方案1】:

您可以利用引用不可泛化这一事实。

# let id = let rx = ref [] in fun x -> rx := [x]; rx := []; x;;
val id : '_weak1 -> '_weak1 = <fun>

我认为引用的这个属性不太可能改变。

我假设你想要的是这个版本的 id 在第一次实际使用时假设一个单一的单态类型:

# id "yes";;
- : string = "yes"
# id;;
- : string -> string = <fun>

如果您在实际代码中使用它,则需要在其模块结束之前获取具体类型。你不能让弱类型变量未定义,否则你会得到这个错误:

Error: The type of this expression, '_weak1 -> '_weak1,
       contains type variables that cannot be generalized

【讨论】:

    【解决方案2】:

    另外两个答案基本上利用了只有 values 是泛化的事实,因此,如果您将定义包装在不是值的东西中,它就不会被泛化。因此,将其赋予 id 函数的技巧。

    但是,如果考虑到放宽的值限制,它就不起作用了:

    # let nil = id [] ;;
    val nil : 'a list = []
    

    因此,您需要确保所需的类型变量不会出现在协变位置。在您的第一个示例中,它出现在箭头的左侧,所以很好。否则,您需要通过隐藏类型定义并省略方差注释来确保它正常工作。

    module M : sig
      type 'a t
      val make : 'a list -> 'a t
    end = struct
      type 'a t = 'a list
      let make x = x
    end
    
    let x = M.make []
    val x : '_weak1 M.t
    

    【讨论】:

      【解决方案3】:

      我同意Jeffrey Scofield's answer,但在我看来,最好避免引用,没有它们你可以实现相同的行为:

      # let id = let id = fun x -> x in id id;;
      val id : '_weak1 -> '_weak1 = <fun>
      

      之后,如果您需要带有其他签名的函数,例如eq : '_weak2 -&gt; '_weak2 -&gt; bool,那么您只需以正常方式实现eq并将其传递给id

      # let eq =
          let id = let id = fun x -> x in id id in
          let eq = (=) in (id (eq));;
      val eq : '_weak2 -> '_weak2 -> bool = <fun>
      

      【讨论】:

      • 你不需要所有这些扭曲。 let id x = x ;; let eq = id (=) ;; 绰绰有余。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-11-25
      • 2021-07-20
      • 2011-04-22
      • 1970-01-01
      • 2019-10-30
      • 1970-01-01
      • 2022-07-05
      相关资源
      最近更新 更多