不能一概而论的变量
Variables that cannot be generalized
我正在尝试创建具有 Hashtable 值的 Hashtable,如下所示:
let map = ((Hashtbl.create 100) : ((int, (_,int) Hashtbl.t) Hashtbl.t ));;
但不幸的是,转换类型对我没有帮助,编译器说:
"Batteries.Hashtbl.t, contains type variables that cannot be generalized"。我该如何解决这个问题?
您显然希望包含的散列 table 的键是任何类型。但这是不可能的,OCaml 是一种强类型语言。
如果你事先知道类型,你可以创建一个变体类型,它将不同类型的标记值收集在一起,并从中产生一种类型。
执行此操作的一种方法可能如下所示,其中每个内部散列 table 具有单个一致的密钥类型。
type intstrHT = IntHT of (int, int) Hashtbl.t |
StrHT of (string, int) Hashtbl.t
let map : (int, intstrHT) Hashtbl.t = Hashtbl.create 100
另一种可能是您希望在同一个散列中使用不同类型的键 table:
type intstr = Int of int | Str of string
let map : (int, (intstr, int) Hashtbl.t) Hashtbl.t = Hashtbl.create 100
更新
您不能使用未指定密钥类型的散列 table。请注意以下会话:
$ ocaml
OCaml version 4.02.1
# let map : (_, int) Hashtbl.t = Hashtbl.create 100;;
val map : ('_a, int) Hashtbl.t = <abstr>
# Hashtbl.add map "yes" 15;;
- : unit = ()
# Hashtbl.add map 44 88;;
Error: This expression has type int but an expression was expected of type
string
# map;;
- : (string, int) Hashtbl.t = <abstr>
您可以将密钥的类型声明为"unspecified,",但这只是意味着稍后会弄清楚。您仍然只能拥有一种类型的密钥。在上面,编译器计算出你的键类型是 string
.
如果编译器无法在模块末尾确定您的密钥类型,您将得到与您看到的相同的 "cannot be generalized" 错误。
$ cat gk.ml
let map : (_, int) Hashtbl.t = Hashtbl.create 100
$ ocamlc -c gk.ml
File "gk.ml", line 1, characters 31-49:
Error: The type of this expression, ('_a, int) Hashtbl.t,
contains type variables that cannot be generalized
更新 2
您还可以声明一个函数,它接受不同类型的值。函数可以是多态的,但特定的容器不能。
# let f (x: (_, int) Hashtbl.t) y = Hashtbl.find x y;;
val f : ('a, int) Hashtbl.t -> 'a -> int = <fun>
此函数可以接受具有不同密钥类型的散列 table。但是没有一个散列 table 可以有超过一种键类型。
我正在尝试创建具有 Hashtable 值的 Hashtable,如下所示:
let map = ((Hashtbl.create 100) : ((int, (_,int) Hashtbl.t) Hashtbl.t ));;
但不幸的是,转换类型对我没有帮助,编译器说: "Batteries.Hashtbl.t, contains type variables that cannot be generalized"。我该如何解决这个问题?
您显然希望包含的散列 table 的键是任何类型。但这是不可能的,OCaml 是一种强类型语言。
如果你事先知道类型,你可以创建一个变体类型,它将不同类型的标记值收集在一起,并从中产生一种类型。
执行此操作的一种方法可能如下所示,其中每个内部散列 table 具有单个一致的密钥类型。
type intstrHT = IntHT of (int, int) Hashtbl.t |
StrHT of (string, int) Hashtbl.t
let map : (int, intstrHT) Hashtbl.t = Hashtbl.create 100
另一种可能是您希望在同一个散列中使用不同类型的键 table:
type intstr = Int of int | Str of string
let map : (int, (intstr, int) Hashtbl.t) Hashtbl.t = Hashtbl.create 100
更新
您不能使用未指定密钥类型的散列 table。请注意以下会话:
$ ocaml
OCaml version 4.02.1
# let map : (_, int) Hashtbl.t = Hashtbl.create 100;;
val map : ('_a, int) Hashtbl.t = <abstr>
# Hashtbl.add map "yes" 15;;
- : unit = ()
# Hashtbl.add map 44 88;;
Error: This expression has type int but an expression was expected of type
string
# map;;
- : (string, int) Hashtbl.t = <abstr>
您可以将密钥的类型声明为"unspecified,",但这只是意味着稍后会弄清楚。您仍然只能拥有一种类型的密钥。在上面,编译器计算出你的键类型是 string
.
如果编译器无法在模块末尾确定您的密钥类型,您将得到与您看到的相同的 "cannot be generalized" 错误。
$ cat gk.ml
let map : (_, int) Hashtbl.t = Hashtbl.create 100
$ ocamlc -c gk.ml
File "gk.ml", line 1, characters 31-49:
Error: The type of this expression, ('_a, int) Hashtbl.t,
contains type variables that cannot be generalized
更新 2
您还可以声明一个函数,它接受不同类型的值。函数可以是多态的,但特定的容器不能。
# let f (x: (_, int) Hashtbl.t) y = Hashtbl.find x y;;
val f : ('a, int) Hashtbl.t -> 'a -> int = <fun>
此函数可以接受具有不同密钥类型的散列 table。但是没有一个散列 table 可以有超过一种键类型。