Can I Access Parameters of a Computation Expression?

215 Views Asked by At

Is it possible to create methods or stand-alone functions in a computation expression that can later be used by one of the canonical methods of a computation expression?

I want something like this:

type FormletBuilder(ctx : HttpContext) =

    let get_int = 
        match Int32.TryParse (ctx.Request.["foo"]) with
        | (true, n) -> Some n
        | _ -> None

    //similar definitions for get_date, get_non_empty_str, etc...

    member x.Bind (read : 'a option, f : 'a -> option 'a) =
        match read with
        | Some x -> f(x)
        | None -> None      

    member x.Return (obj) = Some obj
    member x.Zero () = None



    let person = formlet ctx {

        let! id = get_int "id"
        let! name = get_non_empty_str "fullname"

        return Person(id, name)
    }

But the compiler complains that get_int is not defined.

2

There are 2 best solutions below

1
On BEST ANSWER

let bindings in class definitions are always private. You can define a member instead.

For an easy solution, you could do:

let formlet = FormletBuilder(ctx)
let person = formlet {
    let! id = formlet.get_int "id"
    ...
}
2
On

I understand now that what you actually want is a maybe monad, and the workflow argument is there just to make use of some syntactic sugar? If so, there are a couple other things you can consider doing:

  1. Go Haskell on it all the way and implement a MaybeReader monad, so that both the maybe and the reader parts of it are explicit in type,
  2. Put the sugar away - I understand you don't actually need the context in any core builder members? If so, than maybe it had no business being an argument to the builder in the first place. Have a 'clean' maybe monad, move get_int etc. into a proper module and have them take HttpContext explicitly as an argument.
  3. If you're using F# 3.0 or later, you can define get_int etc. as custom operations of the workflow, which should effectively give you the nice syntax you want to have. Here's a good post about it by Tomas Petricek.
  4. Combine 2. and 3. - instead of a large number of custom operations, have one - ask - which will take an HttpContext -> 'a function and apply ctx to it. Effectively a bastardized version of reader. Then you can move your get_int etc. into a proper module.