我可以在 F# 成员函数上指定函数类型吗?

Can I specify a function type on F# member functions?

我目前正在尝试使用 F# 中的 Eto.Forms。我 运行 遇到的一个小烦恼是,当您在外部文件(XAML 或 JSON)中定义 GUI 对象(表单、面板、按钮等)并声明事件处理程序时,这些事件处理程序必须具有特定类型:

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

类型签名的重复困扰着我。 (这两个函数实际上有很多重复,比如使用几乎没有变化的参数调用 MessageBox,但这只是一个测试项目。在实际项目中,我会对这两个按钮做一些不同的事情。)我我不想每次都重复这些函数的类型签名。看完this page at F Sharp For Fun and Profit,我想我可以做这样的事情:

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

然而,当我尝试这个时,我发现在成员函数中,语法 实际上 意味着 "This function returns an EventHandler function"。我想说"This member function is an EventHandler function",但我不知道怎么说

更新: 自从写了上面的问题,我了解到我实际上不必指定事件处理函数参数的类型签名。以下将起作用:

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

但是,我真正的问题不是 "how can I make these event handlers work?" 我真正的问题是,"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?"

我将使用一些更简单的类型,但这里的想法是一样的。

考虑一个简单的类型:

type t() = member x.Test()  = ();;

这里 Test 显然有类型 unit -> unit

现在,我们尝试重写它以避免 ()

type t() = member x.Test : unit -> unit  = ();;

但这会失败,因为右侧的值不正确。

这是一种解决方案:

type t() = member x.Test : unit -> unit  = fun () -> () ;;

您可能会尝试更接近您想要的一种解决方案是对忽略的参数使用 _

type t() = member x.Test _ : unit -> unit  =  () ;;

但这行不通,因为我们现在是一个接受单个参数的函数和 returns 一个函数。

此时,我们真正想要的是 Signature file 允许指定成员的类型签名。或者你可以尝试一个界面。

最后一种方法是将参数移动到函数内部 - 然后它将变成

type t() = member x.Test : some signature = fun .....

独立函数定义和方法定义之间的唯一区别是 member 关键字和自我标识符。除此之外,语法相同。

再次检查 F# for fun and profit

上的示例
type AdditionFunction = int->int->int
let f:AdditionFunction = fun a b -> a + b

其实是值绑定,不是函数绑定。该函数使用 lambda 表达式 fun a b -> a + b 定义并绑定到标识符 f.

要使用这种定义,您必须将事件处理程序定义为

type EventHandler = (Object * EventArgs) -> unit

member public this.OnFirstButtonClicked : EventHandler =
    fun (_, _) ->
        MessageBox.Show(this, "First button was clicked")
        |> ignore

同样,独立函数的工作原理完全相同。