简体   繁体   中英

Type inference problems in F#

Using F# in Visual Studio, I find myself having to explicitly annotate types a lot more that I would like, or should have to. I am aware of some techniques for resolving this, in particular the use of the excellent forward piping operator. However, in many circumstances I am unable to avoid doing so, and some of them seem just plain wrong.

For example, I have F# code like the following snippet:

    let b = new pqBoard(this)
    let b2,steps = b.Solve()
    if b2.Solved() then 
        let cont = steps |> List.exists (fun (s : string) -> s.IndexOf("Contradiction") >= 0 )

The third line generates an error message suggesting a type annotation is required for the first of the pair returned from the call to the Solve method on the previous line. But the second element of the pair (a list of strings) is fine, and requires no such annotation. How is it that the type checker can seemingly be certain of the type of the second of the pair, but not of the first when the are returned from a single call?

Changing the second line as follows fixes the problem:

let (b2 : pqBoard,steps) = b.Solve()

Why must I explicitly type the first element and not the second?

Furthermore, in this case and many others, inferred types are correctly displayed by VS in the tooltips. I assume that the VS editor is "guessing" in some sense, but I have yet to see it guess incorrectly!

I find it frustrating and disappointing to have to explicitly provide types without any good idea of why they are required. Any help would be appreciated.

Without seeing the definition of pqBoard and the Solve member it's hard to be sure exactly what's going on, but the key difference between b2 and steps in your sample is how they are used as opposed to how they are generated.

In the case of steps , it's passed into List.exists , which must take list<'a> for some 'a , and the function argument is explicitly annotated to take string , so the type-checker can immediately see that steps must be of type list<string> .

For b2 , a member function is being called. There could be a lot of types with a member function named Solved , and F# doesn't have any way to resolve which of those types is being called without somehow knowing the type of b2 .

In general - though it's not universal - using . in F# will often require the type of the thing on the left-hand side of the . to be explicitly specified somewhere earlier, whereas using the more "functional" constructs and types won't.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM