【问题标题】:Can I specify a function type on F# member functions?我可以在 F# 成员函数上指定函数类型吗?
【发布时间】:2015-10-02 02:35:49
【问题描述】:

我目前正在使用 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

但是,当我尝试这个时,我发现在成员函数中,语法 实际上 的意思是“这个函数返回一个 EventHandler 函数”。我想说“这个成员函数一个EventHandler函数”,我不知道该怎么做。

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

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

但是,我真正的问题不是“我怎样才能使这些事件处理程序工作?”我真正的问题是,“我已经学会了如何指定一个不是类成员的函数的类型,但是对于一个是 一个班级的成员?”

【问题讨论】:

    标签: f# unit-type


    【解决方案1】:

    独立函数定义和方法定义之间的唯一区别是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
    

    同样,它对独立函数的工作方式完全相同。

    【讨论】:

      【解决方案2】:

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

      考虑一个简单类型:

      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  =  () ;;
      

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

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

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

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

      【讨论】:

      • 我对 F# 语法还不够熟悉:在您的第二个示例中,为什么最后需要 = ()?为什么第二个例子不能是type t() = member x.Test : unit -> unit;; —— 那不是有效吗?事实上,为什么所有这些都需要= ()?我认为type TupleToIntFunc = (int * int) -> int 是正确的语法。
      • 在F#中,总是需要提供函数的实现——即使只是()
      猜你喜欢
      • 2014-11-12
      • 1970-01-01
      • 1970-01-01
      • 2011-06-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-07-23
      • 2015-01-15
      相关资源
      最近更新 更多