Search code examples
.netfunctional-programmingf#mailboxprocessor

F# MailboxProcessor async messed print statements


I am trying to make a bar simulator that is processing orders. The message that is sent to the agent is of this type.

type DTGCafeMessage =
    | OrderDrink of Drink * float
    | LeaveAComment of string

The agent is a bar class implemented below.

type Bar() =
    let dtgCafeAgent =
        MailboxProcessor.Start
            (fun inbox ->
                let rec messageLoop () =
                    async {
                        let! msg = inbox.Receive()

                        match msg with
                        | OrderDrink (drink, amount) ->
                            let drinkPrice : float = getPrice drink
                            let mutable totalPrice = ((drinkPrice: float) * (amount: float))

                            if drink.type' = Coffee then
                                totalPrice <- dgtVAT totalPrice VAT

                            printfn
                                "Please pay DKK%d for your %d %A %A drinks. %s!"
                                (Convert.ToInt32(totalPrice))
                                (Convert.ToInt32(amount))
                                (string drink.type')
                                (string drink.size)
                                "Thanks!"
                        | LeaveAComment (comment) -> printf "Comment: %A" comment

                        return! messageLoop ()
                    }

                messageLoop ())

    member this.Order msg = dtgCafeAgent.Post msg


When I send the messages to the agent, it is printing stuff in a very messed way.

let bar = Bar()
let testDrink = { type' = Coffee; size = Small }

bar.Order(OrderDrink({ type' = Coffee; size = Small }, 2.0))

let orderDrinks =
    [ (OrderDrink({ type' = Coffee; size = Small }, 1.0))
      (OrderDrink({ type' = Coffee; size = Medium }, 2.0))
      (OrderDrink({ type' = Juice; size = Small }, 3.0))
      (OrderDrink({ type' = Soda; size = Medium }, 4.0))
      (OrderDrink({ type' = Milk; size = Large }, 5.0)) ]

orderDrinks |> List.map (fun o -> bar.Order o)

// output
> orderDrinks |> List.map (fun o -> bar.Order o);;
valPlease pay DKK24 for your 1  "Coffee" "Small" drinks. Thanks!!
it Please pay DKK72 for your 2 "Coffee" :"Medium" drinks. Thanks!!
 unitPlease pay DKK 45 for your 3 list"Juice" "Small" drinks. Thanks!!
 =Please pay DKK51 for your 4  "Soda" "Medium" drinks. Thanks!!
[()Please pay DKK;125 for your 5 "Milk"  "Large" drinks. Thanks!!
(); (); (); ()]

As I see, it should print every statement as written in the code.


Solution

  • Fsi is evaluating your expression. Since bar.Order() returns unit, the result of your expression is [(); (); (); (); ()]. So Fsi wants to print something like

    val it : unit list = [(); (); (); (); ()]
    

    Meanwhile, the mailbox processor is on another thread working through its queue, printing messages as it does so. The two threads are both sending text to the same output, i.e. they are stepping on each other.