Search code examples
f#mef

F# and MEF: Exporting Functions


So, I was trying to get this simple test working in an F# console app:

open System.Reflection
open System.ComponentModel.Composition
open System.ComponentModel.Composition.Hosting

[<Export(typeof<int -> string>)>]
let toString(i: int) = i.ToString()

[<EntryPoint>]
let main argv = 
    use catalog = new AssemblyCatalog(Assembly.GetEntryAssembly())
    use container = new CompositionContainer(catalog)

    let myFunction = container.GetExportedValue<int -> string>()
    let result = myFunction(5)
    0

I expected MEF to get the function properly resolved, but it doesn't. Instead, I get this:

An unhandled exception of type 'System.ComponentModel.Composition.CompositionContractMismatchException' occurred in System.ComponentModel.Composition.dll

Additional information:

Cannot cast the underlying exported value of type 'Program.toString (ContractName="Microsoft.FSharp.Core.FSharpFunc(System.Int32,System.String)")' to type 'Microsoft.FSharp.Core.FSharpFunc``2[System.Int32,System.String]'.

  • What am I missing here?
  • What is the difference between FSharpFunc(System.Int32, System.String) and FSharpFunc``2[System.Int32, System.String]?
  • What is the correct way to import/export F# functions via MEF?

Solution

  • The compiler turns top-level F# functions into methods, so your example will be compiled as:

    [Export(FSharpFunc<int,string>)]
    public string toString(int i) { return i.ToString(); }
    

    This is probably causing the error. You can force the compiler to produce a property getter of FSharpFunc type by calling some operation that returns a function - even a simple identity function will don:

    let makeFunc f = f 
    
    [<Export(typeof<int -> string>)>]
    let toString = makeFunc <| fun (i:int) -> 
      i.ToString()
    

    I have not tested this, but I think it could work. That said, it is probably safer to go with a simple single-method interface in this case.