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

tig*_*ars 4 f# constructor 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)
Run Code Online (Sandbox Code Playgroud)

让我们想象一下这就是模型,在现实生活中,模型恰好在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
Run Code Online (Sandbox Code Playgroud)

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

编辑:@tomas有一个很好的答案,但在评论中也是一个非常有用的扩展,确保你看看两者.

Tom*_*cek 7

你在这里得到的问题称为值限制 - 基本上,如果你想使用函数作为泛型,它必须被定义为显式函数.

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

let raiseEventForJob1234 f = raise 1234 "other thing" f

raiseEventForJob1234 SomeJobStarted
raiseEventForJob1234 SomeJobComplete
Run Code Online (Sandbox Code Playgroud)

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

  • @tigerswithguitars最简单的方法是使用"currifier"功能.许多图书馆提供它们,或者如果它是一次性的你可以自己编写:`让curry2 f = fun a - > fun b - > f(a,b)`.LMK如果我理解正确的话. (2认同)