I have a Computational Expression Builder which receives a value during construction
type SomeBuilder<'e> (e: 'e) =
member this.Bind(x, fn) = ...
member this.Return x = ...
member this.ReturnFrom x = ...
let buildSome v = SomeBuilder(v)
buildSome 2 {
return 1
}
Now I'd like to access the value e
from within the
Computational Expression via a custom operation so that
buildSome 2 {
return 1 + e()
}
So I really want to access properties/values in the underlying builder object and work with them
I imagine I would need something like
type SomeBuilder<'e> (e: 'e) =
member this.Bind(x, fn) = ...
member this.Return x = ...
member this.ReturnFrom x = ...
[<CustomOperation("e")>]
member this.E () = e
but that doesn't work.
So my question is
a) is something like this possible using CustomOperations and Computational Expressions b) and if it is possible, how?
Disclaimer:
As usual in programming there is a million ways to achieve similar effects
in completely different ways. I am explicitly asking for this particular way
and I am OK if the answer is simply "No". But please refrain from answers that are non answers in the narrowest sense laid out here.
I'm not sure you'll like my answer and whether it's within your boundaries, but you could capture the builder instance using a trick like this:
type SomeBuilder<'e> (e: 'e) =
member this.Value = e
[<CustomOperation("extract", MaintainsVariableSpaceUsingBind = true, AllowIntoPattern = true)>]
member this.Extract (state) = this
member this.Bind(x, fn) = fn x
member this.Return x = x
member this.ReturnFrom x = x
let builder e = new SomeBuilder<_>(e)
let x = builder 1 {
extract into builder // now we've brought builder in the scope
printfn "here we can read the value = %d" builder.Value
return 0
}
To show that primary constructor arguments are in scope for the builder's instance methods:
type SomeBuilder<'e> (e: 'e) =
member __.Bind(x, fn) = fn x
member __.Return x = x
[<CustomOperation("e", MaintainsVariableSpaceUsingBind = true, AllowIntoPattern = true)>]
member __.E _ = e
SomeBuilder 2 {
e into i
return 1 + i }
// val it : int = 3
SomeBuilder "bar" {
e into s
return "foo" + s }
// val it : string = "foobar"
Consider the position of the custom operation inside the builder; it will ignore expressions that precede it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With