2016-05-25 5 views
4

У меня есть пример использования конструктора для производного типа в качестве делегата, и я не могу понять, невозможно ли это, или я просто не могу его обработать.F # использовать конструкторы как функции

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, убедитесь, что вы забронируете оба.

+0

Не совсем новый и я очень хорошо знаю C#. Но у меня нет какой-либо базы знаний, кроме Интернета. Я знаю, как я мог бы сделать это на C#, используя довольно симпатичное отражение knarley, но кажется, что F # должно быть в состоянии сделать это более элегантно. – tigerswithguitars

ответ

7

Проблема, которую вы получаете здесь, называется ограничение значения - в принципе, если вы хотите использовать функцию как общую, ее нужно определить как явную функцию.

В вашем случае raiseEventForJob1234 является общим (он может создавать и запускать различные типы событий), но он определяется как значение. Добавление аргумента решает следующее:

let raiseEventForJob1234 f = raise 1234 "other thing" f 

raiseEventForJob1234 SomeJobStarted 
raiseEventForJob1234 SomeJobComplete 

Также обратите внимание, что это работает только в F # 4.0 (в Visual Studio 2015). Предыдущая версия F # не поддерживала обработку конструкторов как функций.

+0

Это потрясающе! Тогда мне нужно будет больше узнать о значении. Я думал, что currying будет просто обрабатывать это для меня, и значение будет правильной функцией. Я ударил это с помощью параметров функции «void» раньше, не ожидал этого здесь. – tigerswithguitars

+0

Суб-вопрос, так как мы здесь. Есть ли способ передать версию в карри в качестве аргумента без необходимости «указывать» каждую версию с параметром? Наверное, нет. – tigerswithguitars

+2

@tigerswithguitars Самый простой подход - использовать функцию «счётчик». Многие библиотеки предоставляют их, или вы можете написать это самостоятельно, если это одноразовый: 'let curry2 f = fun a -> fun b -> f (a, b)'. LMK, если я правильно вас понял. – piaste

Смежные вопросы