为什么此OCaml代码段的类型错误?
我正在学习OCaml中“记忆化函数”的概念,并尝试自己实现 以下是我编写的代码:为什么此OCaml代码段的类型错误?,ocaml,memoization,Ocaml,Memoization,我正在学习OCaml中“记忆化函数”的概念,并尝试自己实现 以下是我编写的代码: type 'a memo_type = Value of 'a | Exn of exn let memo_func_hash_exp f = let cache = Hashtbl.create 10 in fun v -> try match Hashtbl.find cache v with | Value r -> r | Exn e -&g
type 'a memo_type = Value of 'a | Exn of exn
let memo_func_hash_exp f =
let cache = Hashtbl.create 10 in
fun v ->
try
match Hashtbl.find cache v with
| Value r -> r
| Exn e -> e
with
| Not_found ->
begin
try
let r = f v in
Hashtbl.replace cache v (Value r);
r
with
| e ->
Hashtbl.replace cache v (Exn e);
raise e
end ;;
然而,令我惊讶的是,解释器向我显示了函数memo\u func\u hash\u exp
的类型如下:
val memo_func_hash_exp : ('a -> exn) -> 'a -> exn = <fun>
val memo\u func\u hash\u exp:('a->exn)->'a->exn=
这看起来很奇怪,我不知道实现的哪一部分出错了 考虑此表达式的类型:
match Hashtbl.find cache v with
| Value r -> r
| Exn e -> e
在某些情况下,它返回r
,在其他情况下,它返回e
。因此,它们必须是相同的类型。由于将函数值缓存为r
,将异常缓存为e
,因此r
是异常
如果表中存在异常,则更可能希望引发异常。考虑此表达式的类型:
match Hashtbl.find cache v with
| Value r -> r
| Exn e -> e
在某些情况下,它返回r
,在其他情况下,它返回e
。因此,它们必须是相同的类型。由于将函数值缓存为r
,将异常缓存为e
,因此r
是异常
如果表中存在异常,则更可能希望引发异常。考虑此表达式的类型:
match Hashtbl.find cache v with
| Value r -> r
| Exn e -> e
在某些情况下,它返回r
,在其他情况下,它返回e
。因此,它们必须是相同的类型。由于将函数值缓存为r
,将异常缓存为e
,因此r
是异常
如果表中存在异常,则更可能希望引发异常。考虑此表达式的类型:
match Hashtbl.find cache v with
| Value r -> r
| Exn e -> e
在某些情况下,它返回r
,在其他情况下,它返回e
。因此,它们必须是相同的类型。由于将函数值缓存为r
,将异常缓存为e
,因此r
是异常
如果表中存在异常,则更可能希望引发异常。正如Jeffrey所建议的,当
Exn e
未找到时,这会遇到问题,因为该异常与Hashtbl引发的异常混淆。find
表示表中没有异常。您可以通过重新排列代码以将raise e
移出有问题的try
的范围来避免这种情况:
type 'a memo = Value of 'a | Exn of exn
let memo_func f =
let cache = Hashtbl.create 16 in
fun x ->
let result =
try Hashtbl.find cache x
with Not_found ->
let entry =
try Value (f x)
with e -> Exn e in
Hashtbl.add cache x entry;
entry in
match result with
| Value v -> v
| Exn e -> raise e
正如Jeffrey所建议的,当
Exn e
未找到时,这会遇到麻烦,因为该异常与Hashtbl.find
引发的异常相混淆,以指示表中的缺席。您可以通过重新排列代码以将raise e
移出有问题的try
的范围来避免这种情况:
type 'a memo = Value of 'a | Exn of exn
let memo_func f =
let cache = Hashtbl.create 16 in
fun x ->
let result =
try Hashtbl.find cache x
with Not_found ->
let entry =
try Value (f x)
with e -> Exn e in
Hashtbl.add cache x entry;
entry in
match result with
| Value v -> v
| Exn e -> raise e
正如Jeffrey所建议的,当Exn e
未找到时,这会遇到麻烦,因为该异常与Hashtbl.find
引发的异常相混淆,以指示表中的缺席。您可以通过重新排列代码以将raise e
移出有问题的try
的范围来避免这种情况:
type 'a memo = Value of 'a | Exn of exn
let memo_func f =
let cache = Hashtbl.create 16 in
fun x ->
let result =
try Hashtbl.find cache x
with Not_found ->
let entry =
try Value (f x)
with e -> Exn e in
Hashtbl.add cache x entry;
entry in
match result with
| Value v -> v
| Exn e -> raise e
正如Jeffrey所建议的,当Exn e
未找到时,这会遇到麻烦,因为该异常与Hashtbl.find
引发的异常相混淆,以指示表中的缺席。您可以通过重新排列代码以将raise e
移出有问题的try
的范围来避免这种情况:
type 'a memo = Value of 'a | Exn of exn
let memo_func f =
let cache = Hashtbl.create 16 in
fun x ->
let result =
try Hashtbl.find cache x
with Not_found ->
let entry =
try Value (f x)
with e -> Exn e in
Hashtbl.add cache x entry;
entry in
match result with
| Value v -> v
| Exn e -> raise e
以下是您的代码:
type 'a memo_type = Value of 'a | Exn of exn
let memo_func_hash_exp f =
let cache = Hashtbl.create 10 in
fun v ->
try
match Hashtbl.find cache v with
| Value r -> r
| Exn e -> e
with
| Not_found ->
begin
try
let r = f v in
Hashtbl.replace cache v (Value r);
r
with
| e ->
Hashtbl.replace cache v (Exn e);
raise e
end ;;
让我们把你的代码分解一下
第一个重要部分是
try
match Hashtbl.find cache v with
| Value r -> r
| Exn e -> e
with
基本上,你要做的是1)。如果Hashtbl找到键v
,则返回其值;2). 如果未找到,则抛出异常,外部的try with
将捕获它
但是,代码出现的第一个错误是:您应该提高e
,而不是在之后返回e
无论如何,如果您使用e
而不是raisee
,这部分代码意味着
r的类型
=e的类型
r的类型
=使用
然后,假设它捕获了表示未找到的异常:
| Not_found ->
begin
try
let r = f v in
Hashtbl.replace cache v (Value r);
r
with
| e ->
Hashtbl.replace cache v (Exn e);
raise e
end
你看,和| e->…
在那里,所以e
是exn
,回忆r的类型=e的类型,所以r的类型是exn
所以整个memo\u func\u hash\u exp
将返回exn
的类型,对吗
由于还可能返回r=f v
和r
,因此第二个r
也具有exn
类型
所以总体而言,valmemo\u func\u hash\u exp:('a->exn)->'a->exn=
正确的版本可能是:
type 'a memo_type = Value of 'a | Exn of exn
let memo_func_hash_exp f =
let cache = Hashtbl.create 10 in
fun v ->
if Hashtbl.mem cache v then
match Hashtbl.find cache v with
| Value r -> r
| Exn e -> raise e
else
try let r = f v in Hashtbl.add cache v (Value r); r
with e -> Hashtbl.add cache v (Exn e); raise e
基本上,您首先使用directHashtbl.mem
检查成员资格,这将避免异常混淆(一个exn可能由于找不到而抛出,另一个可能由于f可能抛出的exn而抛出)。下面是您的代码:
type 'a memo_type = Value of 'a | Exn of exn
let memo_func_hash_exp f =
let cache = Hashtbl.create 10 in
fun v ->
try
match Hashtbl.find cache v with
| Value r -> r
| Exn e -> e
with
| Not_found ->
begin
try
let r = f v in
Hashtbl.replace cache v (Value r);
r
with
| e ->
Hashtbl.replace cache v (Exn e);
raise e
end ;;
让我们把你的代码分解一下
第一个重要部分是
try
match Hashtbl.find cache v with
| Value r -> r
| Exn e -> e
with
基本上,你要做的是1)。如果Hashtbl找到键v
,则返回其值;2). 如果未找到,则抛出异常,外部的try with
将捕获它
但是,代码出现的第一个错误是:您应该提高e
,而不是在之后返回e
无论如何,如果您使用e
而不是raisee
,这部分代码意味着
r的类型
=e的类型
r的类型
=使用
然后,假设它捕获了表示未找到的异常:
| Not_found ->
begin
try
let r = f v in
Hashtbl.replace cache v (Value r);
r
with
| e ->
Hashtbl.replace cache v (Exn e);
raise e
end
你看,和| e->…
在那里,所以e
是exn
,回忆r的类型=e的类型,所以r的类型是exn
所以整个memo\u func\u hash\u exp
将返回exn
的类型,对吗
因为
r=f v