F#如何将函数变量传递给成员函数

F#如何将函数变量传递给成员函数,f#,F#,给定具有多个字段的类型(候选人),可以评分(这里是一个带有_scoreXXX的具体示例)并计算总百分比分数: type ScorableCandidate() = let mutable _scoreXXX: int = 0 ; let mutable _percentXXX: float = 0. ; member this.scoreXXX with get() = _scoreXXX and set(v) =

给定具有多个字段的类型(候选人),可以评分(这里是一个带有_scoreXXX的具体示例)并计算总百分比分数:

type ScorableCandidate() =
    let mutable _scoreXXX: int  =  0 ;
    let mutable _percentXXX: float = 0. ;

    member this.scoreXXX
        with get() = _scoreXXX
        and  set(v) =
            _scoreXXX<- v
            propertyChanged.Trigger(this, new PropertyChangedEventArgs("scoreXXX"))

    member this.percentXXX
        with get() = _percentXXX
        and  set(v) =
            _percentXXX <- v
            propertyChanged.Trigger(this, new PropertyChangedEventArgs("percentXXX"))
我的一个想法是传入函数以获取访问权限,这对于getter来说很容易做到,但我似乎无法理解setter。我意识到我可以对此进行反思——但我觉得这可能不是最好的方式。。。在这一点上,我处于:

    let scoreField (accessF : (ScorableCandidate -> int)) (setF : (float -> unit)) =
        let totalScore = List.fold (fun acc (candidate: ScorableCandidate) -> acc + accessF candidate) 0 brokers

        let score (candidate: ScorableCandidate) =
            setF <| (accessF candidate |> float) / float totalScore  * 100.

        if totalScore > 0 then
            List.iter score <| brokers

    scoreField (fun c -> c.scoreXXX) (fun f -> ())
let scoreField(accessF:(ScorableCandidate->int))(setF:(float->unit))=
让totalScore=List.fold(有趣的acc(候选人:ScorableCandidate)->acc+accessF候选人)0
得分(候选人:可评分候选人)=
setF浮动)/浮动总分*100。
如果totalScore>0,则
List.iter分数c.scoreXXX)(乐趣f->())
但我不知道如何(或者是否可能)将setter表示为类型上的lambda函数(可能我可以将instace作为parameter传递给lambda函数并以某种方式调用它)

想法?谢谢

更新发现了这种方法(想法):
为了使API更简单,您可能需要考虑以下选项之一:

  • 使用反射。然后您可以执行
    scoreField“XXX”
    ,并且您的方法可以显式地将
    get\u scoreXXX
    set\u percentXXX
    方法的“XXX”转换为
    MethodInfo
    s。这样做的缺点是,它在编译时不检查方法名,并且会伴随反射而带来性能损失

  • 使用引用语。然后您可以执行
    scoreField c.scoreXXX,c.percentXXX@>
    。这与反射示例的工作原理类似,只是需要进行更多的编译时检查

  • 创建一个表示分数/百分比组合的类型,并为每个类型创建该类型的属性,而不是单独的属性。您的
    ScorePercent
    类可以为分数和百分比设置getter和setter(并发出自己的更改通知)。然后,您可以执行
    scoreField(func->c.XXX)
    ,其中
    XXX
    成员的类型为
    ScorePercent


  • 你在正确的轨道上,但是你的设置器缺少你要设置场的对象。因此
    setF
    的类型应为:

    setF : (ScorableCandidate -> float -> unit)
    
    那么你会像这样使用它:

    let score (candidate: ScorableCandidate) =
        (setF candidate) <| (accessF candidate |> float) / float totalScore  * 100.
    

    因此,如果我理解正确,您需要在一个候选人中存储多个分数(对于各种不同的事情),然后对这些分数进行计算

    在这种情况下,我会考虑把<代码>分数>代码>一个单独的类型,供考生使用,然后你可以轻松地添加多个分数。如果您需要使用

    IPropertyChange
    将分数和百分比作为候选人和通知的直接属性公开,那么您应该能够编写如下内容:

    /// Takes a name of this score item (e.g. XXX) and a 
    /// function to trigger the property changed event
    type Score(name:string, triggerChanged) = 
      let mutable score = 0
      let mutable percent = 0.0
      member x.Score 
        with get() = score 
        and set(v) = 
          score <- v
          triggerChanged("Score" + name)
      member x.Percent 
        with get() = percent 
        and set(v) = 
          percent <- v
          triggerChanged("Percent" + name)
    
    现在,您的参数化函数只需获取一个函数,该函数接受
    ScorableCandidate
    ,并返回一个
    Score
    对象:

    let scores f =     
      let totalScore  = List.fold (fun acc (candidate: ScorableCandidate) -> 
        let so = f candidate // Get 'Score' object
        acc + so.Score) 0 brokers     
     let score (candidate: ScorableCandidate) =     
       let so = f candidate // Get 'Score' object
       so.Percent <- (float so.Score) / float totalScore * 100.0
     if totalScore > 0 then     
       List.iter score <| brokers    
    

    这使得调用
    Score
    函数尽可能容易,而且它也是一种可扩展的解决方案,可以轻松地将其他计算添加到
    Score
    对象中。缺点(例如,与Pavel的直截了当的解决方案相比)是设计
    Score
    类型需要更多的工作(但是,如果只需要在类中直接公开可读属性,那么在
    ScorableCandidate
    中声明新的分数就可以说更容易了,我认为这应该足够了).

    也许我不清楚,我花了一段时间来决定如何表达这个问题,如果我有误导性,我的应用程序。我希望能够将其参数化,这样scoreXXX只是其中一个选项——那里的逻辑(用于评分)可以分散运行在类的多个属性上,而无需专门为其编码。scoreXXX或scoreYYY或scoreZZZ或scoreXYZ等都是不同的成员,我可能想在…@akaphenom上运行此功能-我编辑了我的答案,为您提供了一些其他选项。谢谢。与Pavel Minaev提供的解决方案相比,使用引号有什么好处?@akaphenom-只是打字稍微少一点。@akaphenom:它写得稍微短一些,尽管它让我知道了如何重写我自己的答案:)选择这个解决方案-因为我只开发了一个原型,这很有效。我认为它们都是有效的方法,正如Tomas提到的,重新设计对象层可能是一个更好的计划,但我受到现有RPC层的限制,这在我这方面是不允许的。谢谢大家
    scoreField (fun c -> c.scoreXXX) (fun c f -> c.percentXXX <- f)
    
    /// Takes a name of this score item (e.g. XXX) and a 
    /// function to trigger the property changed event
    type Score(name:string, triggerChanged) = 
      let mutable score = 0
      let mutable percent = 0.0
      member x.Score 
        with get() = score 
        and set(v) = 
          score <- v
          triggerChanged("Score" + name)
      member x.Percent 
        with get() = percent 
        and set(v) = 
          percent <- v
          triggerChanged("Percent" + name)
    
    type ScorableCandidate() as this = 
      // Create trigger function & pass it to Score objects
      let trigger n = propertyChanged.Trigger(this, n)
      let infoXxx = new Score("Xxx", trigger)
      member this.InfoXxx = scoreXxx             // Exposes the whole Score object
      member this.ScoreXxx = scoreXxx.Score      // & individual...
      member this.PercentXxx = scoreXxx.Percent  // ...properties
    
    let scores f =     
      let totalScore  = List.fold (fun acc (candidate: ScorableCandidate) -> 
        let so = f candidate // Get 'Score' object
        acc + so.Score) 0 brokers     
     let score (candidate: ScorableCandidate) =     
       let so = f candidate // Get 'Score' object
       so.Percent <- (float so.Score) / float totalScore * 100.0
     if totalScore > 0 then     
       List.iter score <| brokers    
    
    scores (fun (c:ScorableCandidate) -> c.InfoXxx)