Suppose there is a F#
definitions:
type Either<'a,'b> = | Left of 'a | Right of 'b
let f (i : int) : Either<int, string> =
if i > 0
then Left i
else Right "nothing"
Function f
is used in C#
code:
var a = Library.f(5);
How the result value a
could be pattern matched for data constructors? Something like:
/*
(if a is Left x)
do something with x
(if a is Right y)
do something with y
*/
Using F# discriminated unions from C# is a bit inelegant, because of how they are compiled.
I think the best approach is to define some members (on the F# side) that will simplify using the types from C#. There are multiple options, but the one I prefer is to define TryLeft
and TryRight
methods that behave similarly to Int32.TryParse
(and so they should be familiar to C# developers using your F# API):
open System.Runtime.InteropServices
type Either<'a,'b> =
| Left of 'a
| Right of 'b
member x.TryLeft([<Out>] a:byref<'a>) =
match x with Left v -> a <- v; true | _ -> false
member x.TryRight([<Out>] b:byref<'b>) =
match x with Right v -> b <- v; true | _ -> false
Then you can use the type from C# as follows:
int a;
string s;
if (v.TryLeft(out a)) Console.WriteLine("Number: {0}", a);
else if (v.TryRight(out s)) Console.WriteLine("String: {0}", s);
You lose some of the F# safety by doing this, but that's expected in a language without pattern matching. But the good thing is that anybody familiar with .NET should be able to use the API implemented in F#.
Another alternative would be to define member Match
that takes Func<'a>
and Func<'b>
delegates and invokes the right delegate with the value carried by left/right case. This is a bit nicer from the functional perspective, but it might be less obvious to C# callers.
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