Reputation: 9914
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.
Upvotes: 4
Views: 235
Reputation: 5741
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.
Upvotes: 3
Reputation: 227
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
}
Upvotes: 4