F# Define function to act as delegate to .net Action - f#

in System.Activities.WorkflowApplication there is a delegate property:
public Action<WorkflowApplicationCompletedEventArgs> Completed { get; set; }
In my program so far, I have a variable that is an instance of this class
I want to define an F# function to set that:
let f (e: WorkflowApplicationCompletedEventArgs) =
// body
myInst.Completed <- f
but this produces the error:
Error 102 This expression was expected to have type
Action but here has type
'a -> unit
how do I complete function "f" to satisfy the compiler?

If you pass an anonymous function fun a -> ... to a method or a constructor that expects a System.Action<...> or a System.Func<...>, then it is automatically converted; in any other case, you need to convert it explicitly like #Funk indicated.
let f = System.Action<WorkflowApplicationCompletedEventArgs>(fun e ->
// body
)
myInst.Completed <- f
// Another solution:
let f (e: WorkflowApplicationCompletedEventArgs) =
// body
myInst.Completed <- System.Action<_>(f)

Related

Finding classes implementing an interface, using reflection, and instantiating them in F#

I am trying to achieve the following:
I have an interface, called IBotCommand and a few classes that implement it. I want to find all these classes, through reflection, instantiate an instance of each and put the result in a dictionary.
the interface is the following:
type IBotCommands =
abstract member Name: unit -> string
abstract member Description: unit -> string
abstract member Help: unit -> string
abstract member Execute: MessageEventArgs -> string[] -> string
and the code:
let t = typeof<IBotCommands>
t.Assembly.GetTypes()
|> Seq.filter (fun x -> x.IsSubclassOf(t))
|> Seq.iter (fun x ->
(
let i = Activator.CreateInstance(x) :> IBotCommands
botCommands.[i.Name] <- i
)
)
the issue I have is with the CreateInstance line. CreateInstance returns an obj type that can't be cast to IBotCommands.
I have the same in C# and it works properly but the C# version is using dynamics:
public static IEnumerable<Type> FindClassSubclassOfType<T>()
{
var a = typeof(T)
.Assembly.GetTypes()
.Where(t => t.IsSubclassOf(typeof(T)))
.Select(t => t);
return a.ToList();
}
var types = ReflectionHelper.FindClassSubclassOfType<BotCommand>();
foreach (var t in types)
{
dynamic c = Activator.CreateInstance(t);
BotCommands[c.Name] = c;
}
how can I get this behavior to work in F#?
can you cast an object to an interface in F#? it's my first time using interfaces in F#
In F#, there is a difference between upcast a :> T and downacst a :?> T.
Upcast is used when the compiler statically knows that a implements an interface T. This is useful if you have a value of a concrete class and want to get a value that has a type of an interface.
Downcast is used when the compiler does not statically know whether a implements an interface. In other words, this means that the cast can fail.
In your case, you need a downcast, because the compiler does not know whether obj implements IBotInterface. All you need to do is to add ?:
let i = Activator.CreateInstance(x) :?> IBotCommands
botCommands.[i.Name] <- i

How do I assign a multi-parameter F# function to a C# variable?

I have the following F# function:
let myFSharpFunction : IO.TryTransform<IDatabaseService,EditForm,SyncType,ErrorDescription> =
fun _ _ -> Ok someValue
I would like to use this F# function as a value/delegate in my C# code:
FSharpFunc<IDatabaseService, FSharpFunc<EditForm, FSharpResult<SyncType, ErrorDescription>>> referenceToFSharpFunction = myFSharpFunction;
However, I get an error:
Error CS0428 Cannot convert method group 'myFSharpFunction' to
non-delegate type 'FSharpFunc>>'. Did you intend to invoke the
method?
I then tried:
public delegate FSharpResult<SyncType, ErrorDescription> myDelegate(IDatabaseService database, EditForm editForm);
...
myDelegate someDelegate = myFSharpFunction;
FSharpFunc<IDatabaseService, FSharpFunc<EditForm, FSharpResult<SyncType, ErrorDescription>>> FSharpFuncToInvoke = someDelegate;
However, this attempt also gave me an error:
type 'Sevan.Android.FormsSyncFragment.myDelegate' to
'Microsoft.FSharp.Core.FSharpFunc>>'
Update:
Attempt 1:
I then tried adding the following function to an F# module:
let toFunc2 f = Func<_, _, _> f // f : 'a -> 'b -> 'c
I next updated the C# code to the following:
var referenceToFSharpFunction = toFunc2<IDatabaseService, EditForm, FSharpResult<SyncType, ErrorDescription>>(myFSharpFunction);
But I then received this error:
Cannot convert method group 'FSharpFuncToInvoke' to non-delegate type
'FSharpFunc>>'. Did you intend to invoke
the method?
Attempt 2:
I also tried setting the F# code to the following:
let toFunc2 f = Func<IDatabaseService,EditForm, Result<SyncType,ErrorDescription>> f // f : 'a -> 'b -> 'c
Then within my C#, I attempted this:
var referenceToFSharpFunction = toFunc2<IDatabaseService, EditForm, FSharpResult<SyncType, ErrorDescription>>(myFSharpFunctione);
But that attempt gave me this error:
Error CS0308 The non-generic method
'Mock.toFunc2(FSharpFunc>>)' cannot be used with type arguments
In conclusion, how do I assign a multi-parameter F# function to a C# variable?
If you are defining some F# functionality that should be used by a C# client, then I would strongly recommend exposing all the functionality in a C#-friendly way - that means, doing all the wrapping on the F# side, so that the C# consumer does not have to worry about things like FSharpFunc at all.
It's a bit hard to say how this should work in your case - because your example does not actually show any realistic piece of code - only some kind of adapter with a fairly complex interface - but you could do something along the following lines:
// Your F# function that is used elsewhere in F# code
let myFsharpFunction =
fun _ _ -> Ok someValue
// Your F# logic, exposed as a C#-friendly `System.Func` delegate
let myCsharpFunction =
System.Func<_, _, _>(myFsharpFunction)
The F# function type FSharpFunc is something completely separate from the Func/Action used in C#, so you need to "convert" it by creating the respective type that C# understands, which is easy, but needs to be done for each number of arguments individually.
let toFunc1 f = Func<_, _> f // f : 'a -> 'b
let toFunc2 f = Func<_, _, _> f // f : 'a -> 'b -> 'c
// etc.
let toAction0 f = Action f // f : unit -> unit
let toAction1 f = Action<_> f // f : 'a -> unit
// etc.

Comparing function types in F#

The next test fail. I call GetType directly to a function definition, and then I also call GetType within an inline function. The generated types are not equal.
namespace PocTests
open FsUnit
open NUnit.Framework
module Helpers =
let balance ing gas = ing - gas
[<TestFixture>]
type ``Reflected types`` ()=
[<Test>] member x.
``test type equality with inline use`` () =
let inline (=>) f = f.GetType().FullName, f in
let fullName, fval = (=>) Helpers.balance in
Helpers.balance.GetType().FullName |> should equal (fullName)
How could I get the same type in order to be "comparable".
When you use a function as a value, F# does not give you any guarantees that the two created objects will be the "same". Under the cover the compiler creates a new closure object for each instance, so you will actually get false as the result even when you try something like this:
balance.GetType().FullName = balance.GetType().FullName
This is the intended behavior - when you try comparing functions directly, the compiler will tell you that functions do not satisfy the equality constraint and cannot be compared:
> let balance ing gas = ing - gas;;
val balance : ing:int -> gas:int -> int
> balance = balance;;
error FS0001: The type '(int -> int -> int)' does not support the
'equality' constraint because it is a function type
This means that the best answer to your question is that what you're asking for cannot be done. I think that comparing function values is most likely not a good idea, but perhaps there is a better answer for your specific problem if you provide some more details why you want to do this.
If you really want to perform equality testing on function values, then probably the cleanest approach is to define an interface and test ordinary object equality:
type IFunction =
abstract Invoke : int * int -> int
let wrap f =
{ new IFunction with
member x.Invoke(a, b) = f a b }
Now you can wrap the balance function in an interface implementation that can be compared:
let balance ing gas = ing - gas
let f1 = wrap balance
let f2 = f1
let f3 = wrap balance
f1 = f2 // These two are the same object and are equal
f1 = f3 // These two are different instances and are not equal
every time you call Helpers.balance a new closure is created, so
Helpers.balance.GetType().FullName |> printfn "%A" //output: "Program+main#22-1"
Helpers.balance.GetType().FullName |> printfn "%A" //output: "Program+main#23-2"
with class like (decompiled from compiled exe in c#)
[Serializable]
internal class main#22-1 : OptimizedClosures.FSharpFunc<int, int, int>
{
internal main#22-1()
{
base..ctor();
}
public override int Invoke(int ing, int gas)
{
return Program.Helpers.balance(ing, gas);
}
}

How to get F# quotation for a interface instance method?

In F#, we can create interface instance by object expression, but while I'm trying to use attribute ReflectedDefinition on the instance method, then I cannot get the quotations. The method info is declared in the interface type, not the instance type.
Here is my test code:
module Test
open System
open System.Reflection
open Microsoft.FSharp.Quotations
open Microsoft.FSharp.Quotations.Patterns
open Microsoft.FSharp.Quotations.DerivedPatterns
open Microsoft.FSharp.Quotations.ExprShape
type IMyInterface =
abstract Foo : int -> int
let createMyInterface () =
{ new IMyInterface with
[<ReflectedDefinition>]
member this.Foo a = a + 1 }
let expr =
let a = createMyInterface()
<# a.Foo(42) #>
let rec iterExpr (expr:Expr) =
match expr with
| Call(objectExpr, info, paramExprs) ->
printfn "info: %A" info
printfn "reflected type: %A" info.ReflectedType
match info with
| MethodWithReflectedDefinition methodExpr ->
printfn "%A" methodExpr
| _ -> failwith "No reflected definition"
| ShapeVar _ -> failwithf "TODO: %A" expr
| ShapeLambda _ -> failwithf "TODO: %A" expr
| ShapeCombination _ -> failwithf "TODO: %A" expr
let test() =
iterExpr expr
[<EntryPoint>]
let main argv =
test()
0 // return an integer exit code
If I run it, I got exception:
C:\Users\Xiang\Documents\Inbox\TTTT\bin\Debug>TTTT
info: Int32 Foo(Int32)
reflected type: Test+IMyInterface
Unhandled Exception: System.Exception: No reflected definition
at Microsoft.FSharp.Core.Operators.FailWith[T](String message)
at Test.iterExpr(FSharpExpr expr) in C:\Users\Xiang\Documents\Inbox\TTTT\Program.fs:line 30
at Test.test() in C:\Users\Xiang\Documents\Inbox\TTTT\Program.fs:line 37
at Test.main(String[] argv) in C:\Users\Xiang\Documents\Inbox\TTTT\Program.fs:line 41
And I also checked the generated assembly with dotPeek, it is implemented as a derived class:
[CompilationMapping(SourceConstructFlags.ObjectType)]
[Serializable]
public interface IMyInterface
{
int Foo([In] int obj0);
}
[CompilationMapping(SourceConstructFlags.Closure)]
[Serializable]
[SpecialName]
[StructLayout(LayoutKind.Auto, CharSet = CharSet.Auto)]
internal sealed class createMyInterface\u004014 : Test.IMyInterface
{
public createMyInterface\u004014()
{
base.\u002Ector();
Test.createMyInterface\u004014 createMyInterface14 = this;
}
[ReflectedDefinition]
int Test.IMyInterface.Test\u002DIMyInterface\u002DFoo([In] int obj0)
{
return obj0 + 1;
}
}
So, the problem is, when I call the Foo method in quotation, the Call pattern get MethodInfo which is declared at interface type, which has no definition. So how could I get the actually implementation MethodInfo? and then I can get the quotation of the implementation?
Here's your problem in a nutshell:
You're calling a virtual method through an instance of the type where the method is defined.
You want the quotation to contain a call to the method as defined on the derived class.
This won't work, and isn't limited to interfaces or object expressions:
type A() =
abstract M : unit -> unit
default this.M() = printfn "abstract"
type T() =
inherit A() with
[<ReflectedDefinition>]
override this.M() = printfn "override"
let expr =
let a : A = upcast T()
<# a.M() #>
Fundamentally, the whole point of an object expression is to provide an anonymous implementation of a non-sealed class, so what you're asking for doesn't make sense to me - the compiler only knows that the object is some instance implementing that interface but can't know the concrete type of the instance and therefore can't know which (of potentially many) concrete method to use.

Is it possible to use the pipeline operator to call a method on a returned object?

Is it possible to call a method on a returned object using the pipeline infix operator?
Example, I have a .Net class (Class1) with a method (Method1). I can currently code it like this:
let myclass = new Class1()
let val = myclass.Method1()
I know I could also code it as such
let val = new Class1().Method1()
However I would like to do be able to pipeline it (I am using the ? below where I don't know what to do):
new Class1()
|> ?.Method1()
Furthermore, say I had a method which returns an object, and I want to only reference it if that method didn't return null (otherwise bail?)
new Class1()
|> ?.Method1()
|> ?? ?.Method2()
Or to make it clearer, here is some C# code:
public void foo()
{
var myclass = new Class1();
Class2 class2 = myclass.Method1();
if (class2 == null)
{
return;
}
class2.Method2();
}
You can define something similar to your (??) operator fairly easily (but operators can't start with a question mark):
let (~??) f x =
if (x <> null) then
f x
Unfortunately, your pipelined code will need to be a bit more verbose (also, note that you can drop the new keyword for calling constructors):
Class1()
|> fun x -> x.Method1()
Putting it all together:
Class1()
|> fun x -> x.Method1()
|> ~?? (fun x -> x.Method2())
Using a custom operator as 'kvb' suggests is definitely an option. Another approach that you may find interesting in this case is to define your own 'computation expression' that automatically performs the check for null value at every point you specify. The code that uses it would look like this:
open System.Windows.Forms
// this function returns (0) null, or (1) btn whose parent is
// null or (2) button whose parent is not null
let test = function
| 1 -> new Button(Text = "Button")
| 2 -> new Button(Text = "Button", Parent = new Button(Text = "Parent"))
| _ -> null
let res =
safe { let! btn = test(2) // specify number here for testing
// if btn = null, this part of the computation will not execute
// and the computation expression immediately returns null
printfn "Text = %s" btn.Text
let! parent = btn.Parent // safe access to parent
printfn "Parent = %s" parent.Text // will never be null!
return parent }
As you can see, when you want to use a value that can potentially be 'null', you use let! inside the computation expression. The computation expression can be defined so that it immediately returns null if the value is null and runs the rest of the computation otherwise. Here is the code:
type SafeNullBuilder() =
member x.Return(v) = v
member x.Bind(v, f) =
if v = null then null else f(v)
let safe = new SafeNullBuilder()
BTW: If you want to learn more about this, it is very similar to 'Maybe' monad in Haskell (or computation working with F# option type).

Resources