Can I use delegates directly in a discriminated union in F#? - f#

I have the following:
type CallbackString = delegate of string -> unit
type CallbackByte = delegate of byte[] -> unit
type CallbackType =
| String of CallbackString
| Byte of CallbackByte
since I may have a lot of types adding up, is there a syntax to do something similar to this (that compiles that is):
type CallbackType =
| String of (delegate of string -> unit)
| Byte of (delegate of byte[] -> unit)

If this is API being used entirely from F#, you can avoid making delegates and use functions as first class values directly:
type CallbackType =
| String of (string -> unit)
| Byte of (byte[] -> unit)
If this is going to be used from C# and you want specific delegate types, an alternative would be to use the predefined Action and Func delegates in the System namespace types to handle this:
// Assumes
// open System
type CallbackType =
| String of Action<string>
| Byte of Action<byte[]>

Related

F# - string | int inference on union

I'm pretty sure this isn't possible but thought I'd double check. I guess I'm trying to mimic typescript's union types.
I have a type
type StringOrInt =
| String of string
| Int of int
And then a function
let returnSelf (x: StringOrInt) = x
At the moment the function has to be called like
returnSelf (String "hello")
Is it possible to do
returnSelf "hello"
and infer that it is a valid StringOrInt?
At the moment it's not supported out of the box, but fairly simple generic casting method can be implemented.
Given an example function:
let call v = (* v has inferred type StringOrInt *)
match v with
| String s -> printfn "called a string %s" s
| Int i -> printfn "called an int %i" i
We could eventually call it like so:
(* % is a unary prefix operator *)
call %"abc"
call %1
We need to provide some way to tell how to convert ordinary string/int into StringOrInt type. This can be used by exemplar convention call:
type StringOrInt =
| String of string
| Int of int
static member inline From(i: int) = Int i
static member inline From(s: string) = String s
Here our discriminated union provides two static methods which are responsible for casting. Since they correspond to the same naming convention, we can use them together with F# statically resolved generic type parameters - these are generics that are resolved at compile time unlike the .NET generics which exists also at runtime - to create a casting function (or operator):
(* casting operator *)
let inline (~%) (x: ^A) : ^B =
(^B : (static member From: ^A -> ^B) x)
This way you can use % prefix operator over any type that implements a casting mechanism in form of static From method.

How to pick correct method overload for function composition?

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.

Is there a better way to assign a data type to a field?

I have a variable declared like this:
type Variable = {
name : string
id : int
datatype : Object
}
Later on, I would like to do something like this:
match variable.datatype with
| :? System.Byte -> printf "Byte"
| :? System.Double -> printf "Double"
| _ -> printf -> "Other type"
My initial attempt was to declare variable like so (A):
let variable = { name = "foo"; id = 0; datatype = System.Byte }
However, this results in datatype containing something like <fun:variable#31>, and the match doesn't behave as desired - it always hits the "other" case.
I found a workaround, namely
let variable = { name = "foo"; id = 0; datatype = Unchecked.defaultof<Byte> }. However, this doesn't express the intention as clearly.
How can I improve the declaration of Variable to have datatype contain a Type, so that the declaration in (A) works?
I'm trying to learn F# and .NET, there is no production code or homework involved here. So there aren't any constraints apart from having the desired match behavior on basic value types and possibly string as well. It is obvious that I'm missing some basic knowledge (vocabulary relating to language features, etc) that could solve this problem quite easily, but I've hit a roadblock trying to figure out what that might be.
One solution is to create a simple wrapper type for datatype:
type DataType =
| Byte
| Char
| Int
| Double
| String
(Aside: It looks odd to reuse language keywords in this way.)
The declaration for Variable then becomes:
type Variable = {
name : string
id : int
datatype : DataType
}
Declare variable in the way we wanted: let variable = { name = "foo"; id = 0; datatype = Byte }.
Then writing the match statement in this way does the job:
match variable.datatype with
| Byte -> printf "Byte"
| Double -> printf "Double"
| _ -> printf "Other type"
I think I have one half of an answer. As Fyodor Soikin mentioned, we can use System.Type instead of System.Object.
type Variable = {
name : string
id : int
datatype : System.Type
}
let variable = { name = "foo"; id = 0; datatype = typeof<System.Byte> }
let (|IsType|_|) (vartype: System.Type) (variable: Variable) =
if variable.datatype = vartype then Some () else None
let ByteType = typeof<System.Byte> // why do I need these let-bindings
let DoubleType = typeof<System.Double> // ahead of the match construct ?
match variable with
| IsType ByteType -> printf "Byte"
| IsType DoubleType -> printf "Double"
| _ -> printf "Other type"
Edit: I am still not sure how to write the pattern matching. In particular, I can't figure out why I am not allowed to put typeof<System.Byte> directly in the match part of the code.

overload resolution of F# lambda vs Func

I'm adding a static builder method to a record type like this:
type ThingConfig = { url: string; token : string; } with
static member FromSettings (getSetting : (string -> string)) : ThingConfig =
{
url = getSetting "apiUrl";
token = getSetting "apiToken";
}
I can call it like this:
let config = ThingConfig.FromSettings mySettingsAccessor
Now the tricky part: I'd like to add a second overloaded builder for use from C# (ignore the duplicated implementation for now):
static member FromSettings (getSetting : System.Func<string,string>) : ThingConfig =
{
url = getSetting.Invoke "apiUrl";
token = getSetting.Invoke "apiToken";
}
This works for C#, but breaks my earlier F# call with
error FS0041: A unique overload for method 'FromSettings' could not be determined based on type information prior to this program point. A type annotation may be needed. Candidates: static member ThingConfig.FromSettings : getSetting:(string -> string) -> ThingConfig, static member ThingConfig.FromSettings : getSetting:Func -> ThingConfig
Why can't F# figure out which one to call?
What would that type annotation look like? (Can I annotate the parameter type from the call site?)
Is there a better pattern for this kind of interop? (overloads accepting lambdas from both C# and F#)
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)
Overload resolution is buggy in F#.
I filed already some cases, like this where it is obviously contradicting the spec.
As a workaround you can define the C# overload as an extension method:
module A =
type ThingConfig = { url: string; token : string; } with
static member FromSettings (getSetting : (string -> string)) : ThingConfig =
printfn "F#ish"
{
url = getSetting "apiUrl";
token = getSetting "apiToken";
}
module B =
open A
type ThingConfig with
static member FromSettings (getSetting : System.Func<string,string>) : ThingConfig =
printfn "C#ish"
{
url = getSetting.Invoke "apiUrl";
token = getSetting.Invoke "apiToken";
}
open A
open B
let mySettingsAccessor = fun (x:string) -> x
let mySettingsAccessorAsFunc = System.Func<_,_> (fun (x:string) -> x)
let configA = ThingConfig.FromSettings mySettingsAccessor // prints F#ish
let configB = ThingConfig.FromSettings mySettingsAccessorAsFunc // prints C#ish

Avoid matching discriminated union when type is known

I have some hardware connected to my PC. The hardware consists of two components each with the ability to read some stuff from its surroundings (e.g. temperature).
I communicate with the hardware using a protocol and I have implemented that protocol in F# and I have this (simplified) model:
I can query the hardware about values/readouts of the each of the sub components and each sub component has different values I can query with different types.
type ChannelAResponse =
| Data1 of float
| Data2 of string
type ChannelBResponse =
| Data1 of int
| Data2 of string
type Response =
| ChannelA of ChannelAResponse
| ChannelB of ChannelBResponse
type ResponseMessage =
{ Id : int
Response : Response }
// The `msg` is actually constructed from the data sent from the hardware
// where this `msg` is just an example.
let response = Response.ChannelB <| ChannelBResponse.Data2 "Everything ok"
let msg = {Id=10; Response=response}
A this point I know - from the protocol - that response is Response.ChannelB and it's data is ChannelBResponse.Data2.
Even though I know this, I still have to do something like following to get the actual string value out
let data = match msg.Response with
| Response.ChannelB x ->
match x with
| ChannelBResponse.Data2 y -> y
which is sort of OK because the protocol guarantees that match doesn't fail, but it's cumbersome to write this for all possible combinations.
Is there an easier way to "cast" the msg.Response into a string in this case?
This is equivalent to your incomplete pattern match, but shorter
let (ChannelB(Data2 data)) = msg.Response
// val data : string = "Everything ok"
warning FS0025: Incomplete pattern matches on this expression. For example, the value 'ChannelA (_)' may indicate a case not covered by the pattern(s).

Resources