We have a function converting things like Int32.TryParse from using a byref to using an Option for the return value.
let inline ToOptionFunc refFunction x =
    match refFunction x with
    | true, value  -> Some value
    | false, _     -> None
Stuff like this stopped compiling in .NET Core with the new overloads to TryParse:
let Int32TryParse (x:string) =
     ToOptionFunc Int32.TryParse x // A unique overload for method 'TryParse' could not be determined (...)
I tried many things and accidentally got it to work by writing it like this instead:
let Int32TryParse (x:string) =
     x |> ToOptionFunc Int32.TryParse
I just don't understand why this compiles and the former does not.
In .NET Core, the Int32.TryParse function has some extra overloads - it can parse either string or ReadOnlySpan<char>. The original code stopped working, because the compiler did not know which overload you wanted to use. 
In the version without pipe, the compiler needs to type-check ToOptionFunc Int32.TryParse x. It proceeds from left to right and when it gets to Int32.TryParse, it does not yet know about x (which has a type annotation constraining that to string) and without knowing about x, it cannot know which TryParse you need.
In the version with pipe, the compiler needs to type-check x |> ToOptionFunc Int32.TryParse. It proceeds from left to right and knows that x is string, so it then infers that the function passed to ToOptionFunc must also be taking string - and when it checks Int32.TryParse, it can already uniquely determine the overload.
The summary is, pipe has very nice properties for guiding type-checking!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With