F # General Programming - Using Elements

Suppose I have a family of types that support a specific member function, for example, the Property element below:

 type FooA = {...} with member this.Property = ... type FooB = {...} with member this.Property = ... 

Assume that the Member property returns an integer for each of the specified types. Now I wanted to write a generic function that could do the following:

 let sum (a: 'T) (b: 'U) = a.Property + b.Property 

I use to write the following in C ++:

 template<typename T, typename U> int sum(T a, U b) { return a.Property + b.Property; } 

How will the equivalent implementation be in F #?

+4
source share
3 answers

This can be done in F #, but this is not idiomatic:

 let inline sum ab = (^T : (member Property : int) a) + (^U : (member Property : int) b) 

In general, the common .NET kinds are very different from C ++ templates, so it’s probably worthwhile to first examine their differences before trying to emulate C ++ in F #. The general philosophy of .NET is that operations are defined by nominal types, not structural ones. In your example, you can define an interface that displays the Property property that your two classes implement, and then your sum function will use instances of that interface.

For more information on F # generators, see http://msdn.microsoft.com/en-us/library/dd233215.aspx ; for a brief comparison of .NET templates compared to C ++ templates see http://blogs.msdn.com/b/branbray/archive/2003/11/19/51023.aspx (or really anything that appears at Google ".NET generics C ++ Templates").

+7
source

I think the clean approach in this case (even in F #) is to use basic object-oriented programming and define an interface with the required members (e.g. Property ):

 type IHasProperty = abstract Property : int 

Note that F # indicates that we are declaring an interface because it has only abstract elements and a constructor. Then you can implement the interface in your types:

 type FooA = {...} interface IHasProperty with member this.Property = ... type FooB = {...} interface IHasProperty with member this.Property = ... 

It is worth noting that any type of F # (including records, discriminatory associations and class classes) can implement interfaces. Now a generic function can simply take two arguments of type IHasProperty :

 let sum (a: IHasProperty) (b: IHasProperty) = a.Property + b.Property 

In this case, you don’t even need generics, but there are several tricks that generic tools can do with interfaces - you can require a parameter of type T to implement a specific interface, but this is not necessary here because F # automatically converts arguments from such types, like FooA to the interface when you write sum f1 f2 .

Using interfaces and types that are immutable often makes very good sense in F #. There may be a “more functional” solution to your problem, but this will require more context.

+2
source

C ++ templates roughly use the peculiar relation of "structural static subtyping" (somewhat similar to "duck spelling"), whereas in .NET generics, nominal subtyping is used. As @kvb says, you can emulate C ++ stuff with inline and static member constraints in F #, but be very careful about this. There are several other ways to express a similar relationship; @Tomas shows one (subtyping OO) and the other shows a method dictionary (which knows how to design .Property from a fixed set of types). (If it were Haskell, you could use typeclasses.)

+2
source

All Articles