1

I'm doing an app using F# and I wonder if I could a) Keep the state under the State computation expression (using FSharpx's implementation) and b) be able to modify the state asynchronously (handling the user's input).

I believe I know how to handle each problem separately; either:

  • Keep the state in mutable variables and use async & MailboxProcessor to receive async requests to modify the state
  • Use the state computation expression but not being able to process the user input.

How could I use both the state and the async computation expressions in FSharp or Haskell?

Gus
  • 25,839
  • 2
  • 51
  • 76
Lay González
  • 2,901
  • 21
  • 41
  • How do you want the two to interact? For instance you could use an intermediary to store the asynchronous requests and then have a portion of the state computation expression pull from that the perform the actual update, but that would involve stalling the resultant updates until the state computation checks. I don't believe there is an alternative though without breaking a lot of guarantees about the state computation (since you no longer know when it can change, and can no longer simply stream it through your process as a single immutable value). – Guvante Jan 28 '15 at 17:43
  • I'm finishing my first attempt. When I finish it, I'll post it as an edit to let you know my requirements. Then, any improvement would be welcome. – Lay González Jan 28 '15 at 18:11

1 Answers1

4

Basically there are 2 approaches to combine monads: use monad transformers or create a custom monad by hand which combines both monads.

Since there are no native type classes in F# you usually end up with the latter solution, but you can use F#+ to combine Async and State a-la Haskell and get the desired computation expression.

Here's an example translated from Haskell:

#r @"FSharpPlus.dll"

open FSharpPlus
open FSharpPlus.Data

let print x = async {printfn "%A" x}

#nowarn "0025" // Incomplete pattern match, list is assumed not to be empty.
let code  =
    let inline io (x: Async<_>)  : StateT<_,Async<_>> = liftAsync x
    let pop  = monad {
        let! (x::xs) = get
        do! put xs
        return x}
    monad {
        let! x = pop
        do! io <| print x
        let! y = pop
        do! io <| print y
        return () }

let main = StateT.run code [1..10] >>= fun _ -> result ()

// try Async.RunSynchronously main

See also this and this related questions.

Gus
  • 25,839
  • 2
  • 51
  • 76