任何人都知道这段代码的问题是什么?
let rec Foo(a,b) =
match a () with
| None -> Some(b)
| Some(c) -> Some(Foo(c,b))
这是编译器错误:
“类型不匹配。期待'a但给定'一个选项在统一''a'和''选项'时,结果类型将是无限的”
答案 0 :(得分:8)
让我们尝试重现编译器如何在此处推断类型。
let rec Foo(a,b) =
match a () with
| None -> Some(b)
| Some(c) -> Some(Foo(c,b))
“好的,所以我看到a ()
。a
必须是从unit
到某种类型的函数,我还不知道哪一个。我会称之为{{ 1}}。“
'a
“a : unit -> 'a
的结果与a ()
/ None
模式匹配。因此Some
必须是'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
。等等,我已经{ {1}},即b : 'c
。b : 'd option
和'd
必须是同一类型,但这是不可能的!定义中必定存在错误。我需要报告它。”它确实如此。
答案 1 :(得分:4)
一步一步地解决问题总是有帮助的。如上所述,Foo的类型为:
val Foo : (unit -> 'a option) * 'b -> 'b option
活动模式中的每个表达式必须评估为相同类型。表达式中的第一个模式匹配具有类型:
'b option
因此,其他模式也必须评估为'b option
或'a option
。你在这里的方式,它返回'a option option
。
这是一个特殊的函数,但您可以通过在第二个模式匹配中返回任何选项值来纠正编译器错误。这是我能想到的唯一一个看起来像上面的例子:
let Foo2(a,b) =
match a () with
| None -> Some(b)
| c -> c
HTH。
答案 2 :(得分:1)
您使用a()
作为选项,这是Foo
中的第一个参数,但是,在最后一行c
中是一个类型,但是您将其传递给递归调用
这就是导致错误的原因。
您希望将c
作为选项类型。