Today I had an issue implementing some simple processing inside an iteration in a MailboxProcessor.
At first I tried to do the iteration with Seq.map, but the code in the iteration was never called! Then I switched to using a Seq.iter for the iteration instead, and then the processing was done just fine...
type Agent<'Msg> = MailboxProcessor<'Msg>
...
let agent =
Agent.Start((fun agent ->
let rec loop =
async {
let! msg = agent.Receive()
match msg with
| SensorEvent(id, ts) ->
...
[for x in connections.[id] -> x]
|> Seq.map (fun light_id -> //Seq.iter works just fine here, Seq.map doesn't!
let publish = new Publish<SimulatorBroker.SimLightOffMsg>()
publish.Message <- new SimulatorBroker.SimLightOffMsg(light_id, recom_ts)
peer.Publish(box publish :?> IPublish<_>)
)
|> ignore
return! loop
}
loop), tokenSource.Token)
What I am puzzled about is why I couldn't use Seq.map?.. and now I am wondering if it get optimized away when it isn't assigned to anything?.. or if something else weird happens when you use Seq.map inside a Mailboxprocessor..?
yes, I know Seq.iter is more appropriate for simple iterations that just return 'unit' anyways. But please forgive me, I am still learning ;).
Seq.map
is lazy. It is not evaluated until you ask for the elements of the sequence. You can do a Seq.toList
after the map and it will force it.
Seq.iter
is strict, it goes through all the elements of the sequence.
Try in FSI
Seq.initInfinite id |> Seq.map (fun x -> printfn "%A" x; x)
and
Seq.initInfinite id |> Seq.iter (fun x -> printfn "%A" x)
So in your case if you want to force the execution and ignore the result, Seq.iter
is more appropriate.