Does F# have the same problem as C# where you can't directly use arithmetic operators with generic T types?
Can you write a generic Sum function that would return the sum of any value that supports the arithmetic addition?
Does F# have the same problem as C# where you can't directly use arithmetic operators with generic T types?
Can you write a generic Sum function that would return the sum of any value that supports the arithmetic addition?
F# has some limited support for this. A good general solution probably involves type classes, which are not supported by the CLR in general, or F# in particular.
F# has overloaded arithmetic operators using 'static member constraints' and 'inline' functions. This is the magic that enables e.g. the +
operator to work on both int
s and float
s. You can write inline
functions whose implementations are based on the built in math operators and make some progress, but it is non-trivial to do in general. You might check out e.g. the source code to Array.sum
(in array.fs in FSharp.Core) in the F# source distribution that comes along with the CTP to get a feel.
See also the 'static member constraints' and 'simulate type classes' part of this answer:
http://stackoverflow.com/questions/501069/f-functions-with-generic-parameter-types/501356#501356
as well as various bits of the library like
http://msdn.microsoft.com/en-us/library/ee370581(VS.100).aspx
http://msdn.microsoft.com/en-us/library/ee340262(VS.100).aspx
The best mechanism I'm aware of for performing generic arithmetic is type classes, which sadly neither C#, F#, nor the .Net runtime in general support. However, you can simulate them yourself by hand, as mentioned in this blog post:
Type Classes Are The Secret Sauce
That technique should work in C# 2.0 or later (using anonymous delegates / lambdas).
Often people turn to interfaces, but run into a couple problems
An interface declares that, for all implementations, all the methods on that interface take the same implicit 'this' parameter type. If Foo implements some interface, then obviously the 'this' parameter must be of type Foo for that implementation. But there's no way to require that other method parameters also be of type Foo.
Type classes allow you to (among other things) perform this kind of constraint on all method parameters, not just the first parameter.
As mentioned in the article cited earlier, you can simulate type classes by passing function tables as explicit arguments.
(Community wiki: would post an example from that article translated into C# here, but ran out of time with long-winded explaination)
You could do something like this.
let inline sum<'a when 'a : (static member (+) : 'a -> 'a -> 'a)> a b =
a + b
let result = sum<int> 3 4
However if I try let result = sum 3 4
I get the error "type ambiguity inherent in the use of the operator '( + )'"
As brian mentioned, there is some built-in support for generic arithmethic and you can use 'static constraints' which allow you to define some generic functions yourself (although this is a bit limited).
In addition to this, you can also use dynamic 'numeric associations', which is a bit slower when using in a function, but it can be nicely used for example to define your own vector or matrix type. Here is an example:
#r "FSharp.PowerPack.dll"
open Microsoft.FSharp.Math
let twoTimesLarger (n:'a) (m:'a) =
let ops = GlobalAssociations.GetNumericAssociation<'a>()
let sel = if ops.Compare(n, m) > 0 then n else m
ops.Multiply(sel, ops.Add(ops.One, ops.One))
We first need to reference F# PowerPack library which contains the functionality. Then we define a generic function with a signature 'a -> 'a -> 'a
. The first line dynamically gets numeric operations for working with the type 'a
(it essentially uses some lookup table with the type as the key). Then you can use methods of the numeric operations object to perform things like multiplication, addition (Multiply
, Add
) and many others. The function works with any numbers:
twoTimesLarger 3 4
twoTimesLarger 2.3 2.4
twoTimesLarger "a" "b" // Throws an exception!
When you define your own numeric type, you can define its numeric operations and register them using GlobalAssociations.RegisterNumericAssociation
. I believe this also means that you'll be able to use built-in F# Matrix<YourType>
and Vector<YourType>
after registering the operations.