有人知道这段代码有什么问题吗?
let rec Foo(a,b) =
match a () with
| None -> Some(b)
| Some(c) -> Some(Foo(c,b))
这是编译器错误:
“类型不匹配。期望一个 'a 但给定一个 'a 选项当统一 ''a' 和 ''a option' 时,结果类型将是无限的”
有人知道这段代码有什么问题吗?
let rec Foo(a,b) =
match a () with
| None -> Some(b)
| Some(c) -> Some(Foo(c,b))
这是编译器错误:
“类型不匹配。期望一个 'a 但给定一个 'a 选项当统一 ''a' 和 ''a option' 时,结果类型将是无限的”
让我们尝试重现编译器如何尝试在此处推断类型。
let rec Foo(a,b) =
match a () with
| None -> Some(b)
| Some(c) -> Some(Foo(c,b))
“好吧,我明白了a ()
。a
一定是unit
某种类型的函数,我还不知道是哪一种。我会调用它'a
。”
a : unit -> 'a
“的结果a ()
与None
/Some
模式匹配。所以'a
必须是 a'b option
并且c
类型为'b
。” (同样,'b
代表一个未知的,到目前为止,类型)。
a : unit -> 'b option
с : 'b
“没有调用任何函数或方法b
(除了Some
,它不会缩小类型范围,以及Foo
,我们目前还不知道的类型)。我将用它来表示它的类型'c
。”
a : unit -> 'b option
b : 'c
c : 'b
"在其中一个分支中Foo
返回Some(b)
,因此返回类型必须是'c option
."
Foo : (unit -> 'b option) * 'c -> 'c option
“我完成了吗?不,我需要检查表达式中的所有类型是否有意义。让我们看看,在这种Some(c)
情况下,Some(Foo(c,b))
返回。所以Foo(c,b) : 'c
。既然Foo
返回一个option
,我知道'c
一定是'd option
一些'd
,和b : 'd
。等等,我已经有b : 'c
,也就是b : 'd option
. 'd
,'d option
必须是同一个类型,但这是不可能的!定义肯定有错误,我需要报告。” 确实如此。
它总是有助于逐步分解事情。如所写, Foo 具有以下类型:
val Foo : (unit -> 'a option) * 'b -> 'b option
活动模式中的每个表达式必须计算为相同的类型。表达式中的第一个模式匹配具有以下类型:
'b option
因此,其他模式也必须评估为'b option
or 'a option
。你在这里拥有它的方式,它正在返回'a option option
。
这是一个特殊的函数,但您可以通过在第二个模式匹配中返回任何选项值来纠正编译器错误。这是我能想到的唯一一个看起来像上面的例子:
let Foo2(a,b) =
match a () with
| None -> Some(b)
| c -> c
HTH。
您正在使用a()
作为选项,它是 中的第一个参数Foo
,但是,在最后一行c
是一个类型,但是您将它传递给递归调用。
这就是导致错误的原因。
您将希望c
成为选项类型。