F#: Can someone explain my compiler error?

那年仲夏 提交于 2019-12-11 01:05:38

问题


Anyone know what the problem with this code is?

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

Here's the compiler error:

"Type mismatch. Expecting a 'a but given a 'a option The resulting type would be infinite when unifying ''a' and ''a option'"


回答1:


Let's try to reproduce how the compiler tries to infer types here.

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

"Ok, so I see a (). a must be a function from unit to some type, I don't know which one yet. I'll call it 'a."

a : unit -> 'a

"The result of a () is matched with None/Some patterns. So 'a must be a 'b option and c has the type 'b." (Again, 'b stands for an unknown, as of yet, type).

a : unit -> 'b option
с : 'b

"No functions or methods are called on b (except Some, which doesn't narrow the type down, and Foo, the type of which we don't know so far). I'll denote its type by 'c."

a : unit -> 'b option
b : 'c
c : 'b

"Foo returns Some(b) in one of the branches, so the return type must be 'c option."

Foo : (unit -> 'b option) * 'c -> 'c option

"Am I done yet? No, I need to check that all types in the expression make sense. Let's see, in the Some(c) case, Some(Foo(c,b)) is returned. So Foo(c,b) : 'c. Since Foo returns an option, I know 'c must be 'd option for some 'd, and b : 'd. Wait, I already have b : 'c, that is, b : 'd option. 'd and 'd option have to be the same type, but this is impossible! There must be an error in the definition. I need to report it." So it does.




回答2:


It always helps to break things down step-by-step. As written, Foo has the type:

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

Each expression in an active pattern must evaluate to the same type. The first pattern match in your expression has the type:

'b option

Therefore, the other pattern must also evaluate to 'b option or 'a option. The way that you have it here, it is returning 'a option option.

This is a peculiar function but you could correct the compiler error by returning any option value in the second pattern match. Here is the only example that I can think of that looks anything like the above:

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

HTH.




回答3:


You are using a() as an option which is the first parameter in Foo, but, in the last line c is a type, and yet you pass it into the recursive call.

That is what is leading to the error.

You will want to either have c be an option type.



来源:https://stackoverflow.com/questions/1972419/f-can-someone-explain-my-compiler-error

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!