2009-12-29 43 views
2

任何人都知道这段代码的问题是什么?F#:有人可以解释我的编译器错误吗?

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

这里的编译器错误:“类型不匹配期待‘一个,但给定一个‘一个选项统一‘’A’和'一个选项’时,得到的类型将是无限的”

+4

只是为了方便,你究竟要做什么*可能有人会建议一种更好的方式来编写你的功能 – Juliet 2009-12-29 01:24:53

+0

@Juliet - 我不觉得舒服进入一个更好的方式来写功能而不知道,但是,直到你提到它,我没有想到我因为缺乏理解而停下来的事实。 – 2009-12-29 02:01:44

回答

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必须是'b optionc具有类型'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对于某些'db : 'd必须是'd option。等等,我已经有b : 'c,也就是b : 'd option'd'd option必须是相同的类型,但这是不可能的!定义中必须有错误。我需要报告它。“所以它的确如此。”

+1

非常好的分解,换句话说,编译器在'a和'选项选项选项选项选项等选项之间被撕掉了。 – YotaXP 2009-12-30 13:50:02

1

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

这就是导致错误的原因。

你会想要c是一个选项类型。

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

_As written_,'Foo'没有这种类型,并且实际上没有任何其他类型;这就是错误的要点! – 2009-12-29 12:34:09

+2

我理解你的观点,但是我从Visual Studio中的F#解释器中复制了该签名。是的,代码不会按照所示进行编译或运行,但是F#确实对它做了很大的努力=) – 2009-12-29 13:01:26

相关问题