How do I convert a C# tuple into an F# tuple? - f#

How do I convert a C# tuple into an F# tuple?
Specifically, I have a C# implementation of a Result type:
public class Result<T,E>
{
public Result(T data) => Ok = (true,data);
public Result(E data) => Error = (true,data);
public (bool,T) Ok { get; }
public (bool,E) Error { get; }
}
I want to take the tuple value of an Ok result or Error result and use it in my F# code.
Example:
let result = databaseService.getSomething(userIdValue) |> Async.AwaitTask |> Async.RunSynchronously
let isSuccessful,forms = result.Ok
However, I receive the following error:
Error FS0001 One tuple type is a struct tuple, the other is a
reference tuple
In conclusion, I am confused on how to convert a C# tuple into an F# tuple.
I found this link. But I wasn't able to leverage it for what I needed.

C# 7.0 tuple syntax produces ValueTuple values which are different from F# tuples (the older Tuple classes).
Luckilly since F# 4.1 you can use
let struct (isSuccessful, forms) = result.Ok
Notice the extra struct keyword in the pattern. You can use the same syntax to create new ValueTuple values, like let tup = struct (true, 42)

Related

F# incomplete structured construct in my type

I'm trying to implement a OrderedSet in F# (a set where you can get items by order of insertion). This is my first naive attempt at it (I still have to deal with possible duplicates in the IEnumerable passed to the constructor. The comparator is also still missing).
I don't think any of the above matters, though. I've been trying to solve the problem and, as far as I could gather from my research, it seems the issue is about indentation or lack of parentheses somewhere.
If I comment out my attempt at implement ISet, there is no issue, which leads me to believe there is something wrong with that part specifically. Here's the code:
open System
open System.Collections.Generic;
type public OrderedSet<'T> public (collection : IEnumerable<'T> option) as this =
let mutable _set = SortedSet<int * 'T>()
do
if Option.isSome(collection) then
let mapper (idx: int) (elem: 'T) = (idx, elem)
do _set <- SortedSet<int * 'T>(Seq.mapi mapper collection.Value)
interface ISet<'T> with
member this.Count
with get() = this._set.Count
I only had to make two changes:
Indent the if under the do.
Remove this. in front of _set, because it's let-bound, not a class member.
You also have to finish implementing ISet, of course. Here's the resulting code:
open System
open System.Collections.Generic;
type public OrderedSet<'T> public (collection : IEnumerable<'T> option) as this =
let mutable _set = SortedSet<int * 'T>()
do
if Option.isSome(collection) then
let mapper (idx: int) (elem: 'T) = (idx, elem)
do _set <- SortedSet<int * 'T>(Seq.mapi mapper collection.Value)
interface ISet<'T> with
member this.Count
with get() = _set.Count

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.

Unexpected symbol '<-' in binding

I am a F# newbie. What is wrong with this code?
let setCategory (terminal: MerchantTerminal)
terminal.Category <- Nullable(MerchantTerminalCategory.NotSet)
()
Compiler telling me "Unexpected symbol '<-' in binding. Expected '=' or other token"
MerchantTerminal is C# type:
public class MerchantTerminal
{
public MerchantTerminalCategory? Category { get; set; }
}
MerchantTerminalCategory is C# enum
public enum MerchantTerminalCategory
{
NotSet = 0,
//other values
}
You're missing an equal sign in your let definition. It needs to be right before the body, like let x = 5 or let f x = x + 5.
Like this:
let setCategory (terminal: MerchantTerminal) =
terminal.Category <- Nullable(MerchantTerminalCategory.NotSet)
()
A rough Fsharp Equivalent to your C# code:
type MerchantTerminalCategory = NotSet=0 | Set=1
type MerchantTerminal() =
let mutable category =
new System.Nullable<MerchantTerminalCategory>()
member this.Category
with get() = category
and set(value) = category <- value
Usage per your question:
Your usage would look something like this. You were only missing the assignment = op here.
let setCategory (terminal: MerchantTerminal) = //you were missing the assignment "=" op here
terminal.Category <- Nullable(MerchantTerminalCategory.NotSet)
()
Additional comment
As a friendly "code comment" suggestion, one of the benefits of using a construct like that of an enum is to avoid the use of null. If at all possible you should pull out the nullable part and leverage the available states of the enum to represent a default "NotSet" state possibly leveraging what you already have available or via a new state.

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

Using NoRM to access MongoDB from F#

Testing out NoRM https://github.com/atheken/NoRM from F# and trying to find a nice way to use it. Here is the basic C#:
class products
{
public ObjectId _id { get; set; }
public string name { get; set; }
}
using (var c = Mongo.Create("mongodb://127.0.0.1:27017/test"))
{
var col = c.GetCollection<products>();
var res = col.Find();
Console.WriteLine(res.Count().ToString());
}
This works OK but here is how I access it from F#:
type products() =
inherit System.Object()
let mutable id = new ObjectId()
let mutable _name = ""
member x._id with get() = id and set(v) = id <- v
member x.name with get() = _name and set(v) = _name <- v
Is there an easier way to create a class or type to pass to a generic method?
Here is how it is called:
use db = Mongo.Create("mongodb://127.0.0.1:27017/test")
let col = db.GetCollection<products>()
let count = col.Find() |> Seq.length
printfn "%d" count
Have you tried a record type?
type products = {
mutable _id : ObjectId
mutable name : string
}
I don't know if it works, but records are often good when you just need a class that is basically 'a set of fields'.
Just out of curiosity, you can try adding a parameter-less constructor to a record. This is definitely a hack - in fact, it is using a bug in the F# compiler - but it may work:
type Products =
{ mutable _id : ObjectId
mutable name : string }
// Horrible hack: Add member that looks like constructor
member x.``.ctor``() = ()
The member declaration adds a member with a special .NET name that is used for constructors, so .NET thinks it is a constructor. I'd be very careful about using this, but it may work in your scenario, because the member appears as a constructor via Reflection.
If this is the only way to get succinct type declaration that works with libraries like MongoDB, then it will hopefuly motivate the F# team to solve the problem in the future version of the language (e.g. I could easily imagine some special attribute that would force F# compiler to add parameterless constructor).
Here is a pretty light way to define a class close to your C# definition: it has a default constructor but uses public fields instead of getters and setters which might be a problem (I don't know).
type products =
val mutable _id: ObjectId
val mutable name: string
new() = {_id = ObjectId() ; name = ""}
or, if you can use default values for your fields (in this case, all null):
type products() =
[<DefaultValue>] val mutable _id: ObjectId
[<DefaultValue>] val mutable name: string

Resources