Why can't F# figure out which one to call?
Overload resolution in F# is generally more limited than C#. The F# compiler will often, in the interest of safety, reject overloads that C# compiler sees as valid.
However, this specific case is a genuine ambiguity. In the interest of .NET interop, F# compiler has a special provision for lambda expressions: regularly, a lambda expression will be compiled to an F# function, but if the expected type is known to be Func<_,_>, the compiler will convert the lambda to a .NET delegate. This allows us to use .NET APIs built on higher-order functions, such as IEnumerable<_> (aka LINQ), without manually converting every single lambda.
So in your case, the compiler is genuinely confused: did you mean to keep the lambda expression as an F# function and call your F# overload, or did you mean to convert it to Func<_,_> and call the C# overload?
What would the type annotation look like?
To help the compiler out, you can explicitly state the type of the lambda expression to be string -> string, like so:
let cfg = ThingConfig.FromSettings( (fun s -> foo) : string -> string )
A slightly nicer approach would be to define the function outside of the FromSettings call:
let getSetting s = foo
let cfg = ThingConfig.FromSettings( getSetting )
This works fine, because automatic conversion to Func<_,_> only applies to lambda expressions written inline. The compiler will not convert just any function to a .NET delegate. Therefore, declaring getSetting outside of the FromSettings call makes its type unambiguously string -> string, and the overload resolution works.
EDIT: it turns out that the above no longer actually works. The current F# compiler will convert any function to a .NET delegate automatically, so even specifying the type as string -> string doesn't remove the ambiguity. Read on for other options.
Speaking of type annotations - you can choose the other overload in a similar way:
let cfg = ThingConfig.FromSettings( (fun s -> foo) : Func<_,_> )
Or using the Func constructor:
let cfg = ThingConfig.FromSettings( Func<_,_>(fun s -> foo) )
In both cases, the compiler knows that the type of the parameter is Func<_,_>, and so can choose the overload.
Is there a better pattern?
Overloads are generally bad. They, to some extent, obscure what is happening, making for programs that are harder to debug. I've lost count of bugs where C# overload resolution was picking IEnumerable instead of IQueryable, thus pulling the whole database to the .NET side.
What I usually do in these cases, I declare two methods with different names, then use CompiledNameAttribute to give them alternative names when viewed from C#. For example:
type ThingConfig = ...
[<CompiledName "FromSettingsFSharp">]
static member FromSettings (getSetting : (string -> string)) = ...
[<CompiledName "FromSettings">]
static member FromSettingsCSharp (getSetting : Func<string, string>) = ...
This way, the F# code will see two methods, FromSettings and FromSettingsCSharp, while C# code will see the same two methods, but named FromSettingsFSharp and FromSettings respectively. The intellisense experience will be a bit ugly (yet easily understandable!), but the finished code will look exactly the same in both languages.
Easier alternative: idiomatic naming
In F#, it is idiomatic to name functions with first character in the lower case. See the standard library for examples - Seq.empty, String.concat, etc. So what I would actually do in your situation, I would create two methods, one for F# named fromSettings, the other for C# named FromSettings:
type ThingConfig = ...
static member fromSettings (getSetting : string -> string) =
...
static member FromSettings (getSetting : Func<string,string>) =
ThingConfig.fromSettings getSetting.Invoke
(note also that the second method can be implemented in terms of the first one; you don't have to copy&paste the implementation)