F#使用构造函数作为函数

时间:2016-05-25 16:15:05

标签: constructor f# delegates downcast

我有一个用例来处理派生类型的构造函数作为委托,我无法弄清楚它是不可能的,或者我只是无法解决它。

type SomeJobEvent(jobId : int, otherThing : string) =
    member this.JobId = jobId
    member this.OtherThing = otherThing

type SomeJobStarted(jobId : int, otherThing : string) =
    inherit SomeJobEvent(jobId, otherThing)

type SomeJobComplete(jobId : int, otherThing : string) =
    inherit SomeJobEvent(jobId, otherThing)

type SomeJobError(jobId : int, otherThing : string) =
    inherit SomeJobEvent(jobId, otherThing)

让我们想象一下这就是模型,在现实生活中,模型恰好在C#中,我的代码在F#中,但为了简洁起见,在F#中输入更容易。

我想做的是......

let raise eventObject = 
    // This is just a helper, the raise event takes obj.
    eventRaiser.Raise(eventObject)

let raise jobId otherThing eventConstructor = 
    // Lets treat the 'event' constructor as a function
    raise(eventConstructor(jobId, otherThing))

[<EntryPoint>]
let main args = 

    // Lets curry this function up so I don't have to pass around 1234
    let raiseEventForJob1234 = raise 1234 "other thing"

    raiseEventForJob1234 SomeJobStarted

    raiseEventForJob1234 SomeJobComplete

现在,作为传递给raiseEventForJob1234的构造函数具有相同的签名并且是同一继承链的一部分,感觉可能。它只是我不确定如何使它工作,甚至不是他们都嘎嘎叫,他们实际上是鸭子!

修改:@tomas这里有一个很好的答案,但也是Piaste in the comments的一个非常有用的扩展,请确保同时查看两者。

1 个答案:

答案 0 :(得分:7)

您遇到的问题称为值限制 - 基本上,如果您想将函数用作泛型函数,则必须将其定义为显式函数。

在您的情况下,raiseEventForJob1234是通用的(它可以创建和触发不同类型的事件),但它被定义为值。添加参数解决了这个问题:

let raiseEventForJob1234 f = raise 1234 "other thing" f

raiseEventForJob1234 SomeJobStarted
raiseEventForJob1234 SomeJobComplete

另请注意,这仅适用于F#4.0(在Visual Studio 2015中)。以前版本的F#不支持将构造函数视为函数。