Reputation: 36678
I'm currently playing around with using Eto.Forms from F#. One minor annoyance I've run into is that when you define your GUI objects (Forms, Panels, Buttons, etc) in external files (XAML or JSON) and declare event handlers, those event handlers have to have a specific type:
member public this.OnFirstButtonClicked (sender:Object, e:EventArgs) ->
MessageBox.Show(this, "First button was clicked")
|> ignore
member public this.OnSecondButtonClicked (sender:Object, e:EventArgs) ->
MessageBox.Show(this, "Second button was clicked")
|> ignore
The repetition of the type signatures is bothering me. (There's actually a lot of repetition in these two functions, like the calls to MessageBox with barely-varying parameters, but this is just a test project. In a real project, I'd be doing something different for both these buttons.) I'd like to not have to repeat the type signature of each of these functions every time. After reading this page at F Sharp For Fun and Profit, I thought I could do something like this:
type EventHandler = (Object * EventArgs) -> unit
member public this.OnFirstButtonClicked : EventHandler ->
MessageBox.Show(this, "First button was clicked")
|> ignore
member public this.OnSecondButtonClicked : EventHandler ->
MessageBox.Show(this, "Second button was clicked")
|> ignore
However, when I tried this I discovered that on member functions, that syntax actually means "This function returns an EventHandler function". I want to say "This member function is an EventHandler function", and I don't know how to do that.
Update: Since writing the above question, I've learned that I don't actually have to specify the type signatures of the event handler functions' parameters. The following will work:
member public this.OnFirstButtonClicked (sender, e) ->
MessageBox.Show(this, "First button was clicked")
|> ignore
member public this.OnSecondButtonClicked (sender, e) ->
MessageBox.Show(this, "Second button was clicked")
|> ignore
However, my real question isn't "how can I make these event handlers work?" My real question is, "I've learned how to specify the type of a function that isn't a member of a class, but how do I do that for a function that is a member of a class?"
Upvotes: 2
Views: 2207
Reputation: 14896
The only difference between standalone function definition and method definition is the member
keyword and self-identifier. Other than that, the syntax is the same.
Check again the example on F# for fun and profit
type AdditionFunction = int->int->int
let f:AdditionFunction = fun a b -> a + b
It's actually a value binding, not a function binding. The function is defined with a lambda expression fun a b -> a + b
and bound to identifier f.
To use this kind of definition, you would have to define your event handlers as
type EventHandler = (Object * EventArgs) -> unit
member public this.OnFirstButtonClicked : EventHandler =
fun (_, _) ->
MessageBox.Show(this, "First button was clicked")
|> ignore
Again, it works exactly the same for standalone functions.
Upvotes: 3
Reputation: 25516
I am going to use some simpler types, but the idea here is the same.
Consider a simple type:
type t() = member x.Test() = ();;
here Test
clearly has type unit -> unit
Now, we try to rewrite this to avoid the ()
type t() = member x.Test : unit -> unit = ();;
but this will fail because the right hand side has the incorrect value.
Here is one solution:
type t() = member x.Test : unit -> unit = fun () -> () ;;
One solution you might try to get closer to what you want is to use _
for the ignored parameter:
type t() = member x.Test _ : unit -> unit = () ;;
but this won't work, as we are now a function that takes a single argument and returns a function.
At this point, what we actually want is a Signature file that will allow specifying the type signature of a member. Alternatively you could try an interface.
A final method is to move the arguments inside the function - then it would become
type t() = member x.Test : some signature = fun .....
Upvotes: 2