是否可以显式地写下一个非多态类型,但是延迟了统一,比如下划线类型?
因此,在类型检查过程中,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而不是依赖于可能在未来消失的类型系统的限制。
发布于 2018-05-22 05:24:47
您可以利用这样一个事实:引用是不可泛化的。
# 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发布于 2018-05-22 11:03:21
另外两个答案基本上利用了这样一个事实,即只有值是广义的,所以如果将定义封装在不是值的东西中,它就不会被泛化。因此,把它交给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发布于 2018-05-22 07:23:54
我同意Jeffrey Scofield's answer的观点,但在我看来,最好避免引用,您可以在没有引用的情况下实现相同的行为:
# let id = let id = fun x -> x in id id;;
val id : '_weak1 -> '_weak1 = <fun>之后,如果您需要使用其他签名(例如eq : '_weak2 -> '_weak2 -> 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>https://stackoverflow.com/questions/50460061
复制相似问题