Here is a simple composition of functions in F#
let composedFunction = System.Text.Encoding.UTF8.GetBytes >> Array.length
"test" |> composedFunction
Type inference correctly defines the type of composed function string -> int
. But compiler cannot pick correct overload of System.Text.Encoding.UTF8.GetBytes
method:
Error FS0041: A unique overload for method 'GetBytes' could not be determined based on type information prior to this program point. A type annotation may be needed. Candidates:
System.Text.Encoding.GetBytes(chars: char []) : byte [],
System.Text.Encoding.GetBytes(s: string) : byte []Blockquote
Is there any way to compose correct overload of System.Text.Encoding.UTF8.GetBytes
which accepts string parameter?
Or course, I can do following
// declare function which calls correct overload and then use it for compostion
let getBytes (s: string) = System.Text.Encoding.UTF8.GetBytes s
let composedFunction = getBytes >> Array.length
// start composition with ugly lambda
let composedFunction =
(fun (s: string) -> s) >> System.Text.Encoding.UTF8.GetBytes >> Array.length
But I wonder if there is any way without additional function declarations to make the compiler pick right overload according to the inferred string -> int
type of composed function?
You can always add annotations:
let composedFunction : string -> _ = System.Text.Encoding.UTF8.GetBytes >> Array.length
or
let composedFunction = (System.Text.Encoding.UTF8.GetBytes : string -> _) >> Array.length
As your example shows, .NET methods do not always compose well - I think the idiomatic approach in such situations is just to use the .NET style when you're dealing with .NET libraries (and use functional style when you're dealing with functional libraries).
In your specific case, I would just define a normal function with type annotation and get the length using the Length
member rather than using the function:
let composedFunction (s:string) =
System.Text.Encoding.UTF8.GetBytes(s).Length
The existing answer shows how to get the composition to work with type annotations. Another trick you can do (which I would definitely not use in practice) is that you can add identity function on string
to the composition to constrain the types:
let composedFunction = id<string> >> System.Text.Encoding.UTF8.GetBytes >> Array.length
It's fun that this works, but as I said, I would never actually use this, because a normal function as defined above is much easier to understand.
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