4
votes

In this question: In F# how can I produce an expression with a type of Func<obj>? it is shown that a single valued lambda expression is automatically cast/converted to a Func type and then accepted in the function.

I'm working with the MathNet.Numerics library and can confirm this by integrating x^2 between 0 and 10:

#r "../packages/MathNet.Numerics.3.20.0/lib/net40/MathNet.Numerics.dll"
#r "../packages/MathNet.Numerics.FSharp.3.20.0/lib/net40/MathNet.Numerics.FSharp.dll"

#load "Library1.fs"
open Library3

// Define your library scripting code here

open MathNet.Numerics.Integration

let integral = DoubleExponentialTransformation.Integrate((fun x -> x**2.0), 0.0, 10.0, 1.0)

val answer : float = 333.3333333

However, I can't get this to work with multiple valued functions. When I try this I get a type error. Does anyone know a work around for this?

open MathNet.Numerics.Optimization
open MathNet.Numerics.LinearAlgebra.Double

let newAnswer = BfgsSolver.Solve(DenseVector[|1.0, 1.0|], 
                                 (fun x y -> (x + y - 5.0) ** 2.0 + (y - x*x - 4.0) ** 2.0), 
                                 (fun x y -> DenseVector[| 2.0 * (x + y - 5.0) - 4.0 * x * (y - x*x - 4); 
                                                           2.0 * (x + y - 5.0) + 2.0 * (y - x*x - 4.0)   |])
                                                           )

and I get the following error...

Script.fsx(20,34): error FS0193: Type constraint mismatch. The type 
    ''a -> 'b -> 'c'    
is not compatible with type
    'System.Func<MathNet.Numerics.LinearAlgebra.Vector<float>,float>'   
1
Try fun (x, y) -> instead of fun x y -> Not at a PC, will convert to answer later. - CaringDev
@CaringDev I was a bit dismayed to find that doesn't work, at least with my test using IEnumerable.Aggregate - TheQuickBrownFox
@TheQuickBrownFox quite possible... not doing much F# -> C# interaction, can't remember exact circumstances I came across this last. - CaringDev

1 Answers

3
votes

You can use System.Func<_,_,_>() to convert the functions like this:

let newAnswer = BfgsSolver.Solve(DenseVector[|1.0, 1.0|], 
                                 (System.Func<_,_,_>(fun x y -> (x + y - 5.0) ** 2.0 + (y - x*x - 4.0) ** 2.0)),
                                 (System.Func<_,_,_>(fun x y ->
                                    DenseVector[| 2.0 * (x + y - 5.0) - 4.0 * x * (y - x*x - 4)
                                                  2.0 * (x + y - 5.0) + 2.0 * (y - x*x - 4.0) |])))

If you find yourself needing this often you could make code a bit less ugly with a helper:

let f2 f = System.Func<_,_,_> f

UPDATE

Looking at the Math.NET documentation for this method I see now that it actually takes functions with only one input. Maybe you were confused by the Func<A, B> type signature, but in this case A is the input type and B is the output type.

F# functions with one input are converted to Func<_,_> automatically. I downloaded Math.NET and this very minimal example gives no compilation errors:

open MathNet.Numerics.Optimization
open MathNet.Numerics.LinearAlgebra.Double
BfgsSolver.Solve(DenseVector [||], (fun x -> x.[0]), (fun x -> x))

This suggests that the problem is not with converting between function types, but with using functions with the wrong arity. I should've seen this from your original error message!