如何定义此静态解析的类型参数?

时间:2016-06-07 13:27:08

标签: f#

给定的

open System
open System.Windows
open System.Windows.Input
open System.ComponentModel

type RelayCommand (canExecute:(obj -> bool), action:(obj -> unit)) =
    let event = new DelegateEvent<EventHandler>()
    interface ICommand with
        [<CLIEvent>]
        member x.CanExecuteChanged = event.Publish
        member x.CanExecute arg = canExecute(arg)
        member x.Execute arg = action(arg)
    member x.CheckCanExecute (sender:obj) (eventArgs:EventArgs) = event.Trigger([| sender;eventArgs  |])

如何编写静态解析的类型参数化函数,以满足对CheckCanExecute的调用?

虽然这个功能有效,但它无法帮助我学习静态解析的类型参数语法

let checkCanExecute (c:RelayCommand) = c.CheckCanExecute (box this) (EventArgs())

我希望这可以工作

let checkCanExecute (e:^a) = (^a: (member CheckCanExecute: sender:obj -> EventArgs -> unit ) (e, (box me),(EventArgs())))

但是在呼叫现场 checkCanExecute addCommand

我得到方法或对象构造函数'CheckCanExecute'未找到(当使用第二个定义时,第一个编译就好了)

如何定义类let绑定(或成员绑定,如果这是更好的完成工作的方法),使用Statically Resolved Type Parameters能够在任何具有匹配方法签名?

2 个答案:

答案 0 :(得分:5)

如果你想使用SRTP,你不能用普通的方式来理解方法。成员调用语法无法一次处理多个curried参数。

要么像Tomas建议的那样使用.NET风格的tupled声明,要么你必须以member x.f a = fun b -> fun c -> ...形式明确写出currying。

在你的例子中,这意味着:

type RelayCommand
    // ...
    member x.CheckCanExecute sender = fun eventArgs -> 
        event.Trigger([| sender;eventArgs  |])        

let inline checkCanExecute (e:^a) = 
    (^a: (member CheckCanExecute: obj -> (EventArgs -> unit)) (e, (box e)) ) <| EventArgs()

答案 1 :(得分:4)

我认为这里的一些困难是因为CheckCanExecute被定义为一个curried函数。对于成员来说,使用tupled函数可能会更好(编译curried函数的方式很棘手,并且可能会使静态解析的约束混乱)。

如果您按以下方式更改RelayCommand成员:

 member x.CheckCanExecute (sender:obj, eventArgs:EventArgs) =  
   event.Trigger([| sender;eventArgs  |])

并使您的checkCanExecute inline函数需要使用tupled函数:

let inline checkCanExecute (e:^a) = 
  (^a: (member CheckCanExecute: obj * EventArgs -> unit ) (e, box me,(EventArgs())))

然后进行以下类型检查:

checkCanExecute me