今天我遇到了在MailboxProcessor的迭代中实现一些简单处理的问题。
起初我尝试使用Seq.map进行迭代,但迭代中的代码从未被调用过!然后我转而使用Seq.iter进行迭代,然后处理就完成了......
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)
我感到困惑的是为什么我不能使用Seq.map?...现在我想知道它是否在没有被分配给任何东西时被优化掉了? 或者如果在Mailboxprocessor中使用Seq.map会发生其他奇怪的事情..?
是的,我知道Seq.iter更适合简单的迭代,只返回&#39; unit&#39;无论如何。但请原谅我,我还在学习;)。
答案 0 :(得分:4)
Seq.map
很懒。在您询问序列的元素之前,不会对其进行评估。您可以在地图后执行Seq.toList
,它会强行执行。
Seq.iter
是严格的,它贯穿序列的所有元素。
尝试使用FSI
Seq.initInfinite id |> Seq.map (fun x -> printfn "%A" x; x)
和
Seq.initInfinite id |> Seq.iter (fun x -> printfn "%A" x)
因此,在您的情况下,如果您想强制执行并忽略结果,Seq.iter
更合适。
答案 1 :(得分:1)
Seq.map
操作返回一个新序列,其中包含将指定函数应用于输入序列元素的结果。这意味着您只应在需要对结果执行某些操作时使用它。之所以没有做任何事情&#34;是懒惰地评估序列。这意味着使用Seq.map
,您的代码只会构建一个序列,并且不会对其执行任何操作。 (你必须使用ignore
明确忽略结果的事实也表明存在错误)。
编写您正在执行的操作的最简单方法是使用命令式for
循环结构(与Seq.iter
的结构相同):
for light_id in connections.[id] do
let publish = new Publish<SimulatorBroker.SimLightOffMsg>()
publish.Message <- new SimulatorBroker.SimLightOffMsg(light_id, recom_ts)
peer.Publish(box publish :?> IPublish<_>)