2

有人知道这段代码有什么问题吗?

let rec Foo(a,b) =
    match a () with
    | None -> Some(b)
    | Some(c) -> Some(Foo(c,b))

这是编译器错误:

“类型不匹配。期望一个 'a 但给定一个 'a 选项当统一 ''a' 和 ''a option' 时,结果类型将是无限的”

4

3 回答 3

8

让我们尝试重现编译器如何尝试在此处推断类型。

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必须是同一个类型,但这是不可能的!定义肯定有错误,我需要报告。” 确实如此。

于 2009-12-29T13:00:25.493 回答
4

它总是有助于逐步分解事情。如所写, Foo 具有以下类型:

val Foo : (unit -> 'a option) * 'b -> 'b option

活动模式中的每个表达式必须计算为相同的类型。表达式中的第一个模式匹配具有以下类型:

'b option

因此,其他模式也必须评估为'b optionor 'a option。你在这里拥有它的方式,它正在返回'a option option

这是一个特殊的函数,但您可以通过在第二个模式匹配中返回任何选项值来纠正编译器错误。这是我能想到的唯一一个看起来像上面的例子:

let Foo2(a,b) =
    match a () with
    | None -> Some(b)
    | c    -> c

HTH。

于 2009-12-29T02:42:14.213 回答
1

您正在使用a()作为选项,它是 中的第一个参数Foo,但是,在最后一行c是一个类型,但是您将它传递给递归调用。

这就是导致错误的原因。

您将希望c成为选项类型。

于 2009-12-29T01:22:27.400 回答