【问题标题】:How do you define this statically resolved type parameter?你如何定义这个静态解析的类型参数?
【发布时间】:2016-06-08 00:28:50
【问题描述】:

给定

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 -&gt; EventArgs -&gt; unit ) (e, (box me),(EventArgs())))

但在呼叫站点 checkCanExecute addCommand

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

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

【问题讨论】:

    标签: f#


    【解决方案1】:

    我认为这里的一些困难是由于 CheckCanExecute 被定义为柯里化函数这一事实造成的。对于成员来说,最好使用元组函数(柯里化函数的编译方式很棘手,可能会混淆静态解析的约束)。

    如果您更改RelayCommand 成员如下:

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

    并使您的 checkCanExecute 成为需要元组函数的 inline 函数:

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

    然后进行以下类型检查:

    checkCanExecute me
    

    【讨论】:

    • 那么,你不能在 SRTP 中使用柯里化函数?
    • @Maslow:你可以,但你需要用一种不常见的方式把它们写出来。我添加了一个替代答案。
    • @tomas-petricek 不应该 (e, box me, ...) 是 (e, box e, ...) 吗?很抱歉懒得把它提供给编译器看看我是否遗漏了什么:)
    【解决方案2】:

    如果你想使用 SRTP,你不能用普通的方式来柯里化方法。成员调用语法无法同时处理多个柯里化参数。

    您可以按照 Tomas 的建议使用 .NET 样式的元组声明,或者您必须以 member x.f a = fun b -&gt; fun c -&gt; ... 的形式明确写出柯里化。

    在您的示例中,这意味着:

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

    【讨论】:

    • 不错的一个!我无法弄清楚如何使这项工作:)
    • 这似乎仍需要编辑目标方法?但更近了一步。
    猜你喜欢
    • 1970-01-01
    • 2015-12-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-24
    • 1970-01-01
    • 2012-07-11
    相关资源
    最近更新 更多