Это будет что-то вроде
...Bind<'A when 'A :> 'Z>...
но позвольте мне написать код, чтобы убедиться, что это правильно ...
Ах, похоже, это было бы так:
type FinallyBuilder<'z> (finallyAction : 'z -> unit) =
member this.Bind<'a, 'b when 'a :> 'z> (x : 'a, cont : 'a -> 'b) : 'b =
try cont x
finally finallyAction x //(x :> 'z)// illegal
за исключением того, что
http://cs.hubfs.net/forums/thread/10527.aspx
указывает, что F # не имеет ограничений вида "T1:> T2", где оба являются переменными типа (предполагается, что T1 = T2). Однако это может быть хорошо для вашего случая, что именно вы планируете использовать в качестве конкретных экземпляров Z
? Вероятно, существует простой обходной путь или некоторый менее универсальный код, который будет соответствовать сценарию. Например, мне интересно, работает ли это:
type FinallyBuilder<'z> (finallyAction : 'z -> unit) =
member this.Bind<'b> (x : 'z, cont : 'z -> 'b) : 'b = //'
try cont x
finally finallyAction x
Кажется, что:
type FinallyBuilder<'z> (finallyAction : 'z -> unit) =
member this.Bind<'b> (x : 'z, cont : 'z -> 'b) : 'b = // '
try cont x
finally finallyAction x
member this.Zero() = ()
[<AbstractClass>]
type Animal() =
abstract Speak : unit -> unit
let cleanup = FinallyBuilder (fun (a:Animal) -> a.Speak())
type Dog() =
inherit Animal()
override this.Speak() = printfn "woof"
type Cat() =
inherit Animal()
override this.Speak() = printfn "meow"
cleanup {
let! d = new Dog()
let! c = new Cat()
printfn "done"
}
// prints done meow woof
О, я вижу, но d
и c
теперь имеют тип Animal
. Хм, дай мне посмотреть, есть ли во мне остаточный ум ...
Ну, очевидно, вы можете сделать
type FinallyBuilder<'z> (finallyAction : 'z -> unit) =
member this.Bind<'a,'b> (x : 'a, cont : 'a -> 'b) : 'b = // '
try cont x
finally finallyAction (x |> box |> unbox)
member this.Zero() = ()
, который выбрасывает безопасность типов (будет генерировать исключение приведения во время выполнения, если вещь не будет окончательно активна).
Или вы можете сделать строителей для конкретного типа:
type FinallyBuilderAnimal (finallyAction : Animal -> unit) =
member this.Bind<'a,'b when 'a:>Animal>(x : 'a, cont : 'a -> 'b) : 'b = //'
try cont x
finally finallyAction x
member this.Zero() = ()
let cleanup = FinallyBuilderAnimal (fun a -> a.Speak())
Но я думаю, что у меня нет других умных идей.