0

今天我在 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?...现在我想知道当它没有分配给任何东西时它是否会被优化?或者当你使用 Seq 时是否会发生其他奇怪的事情。在邮箱处理器中映射..?

是的,我知道 Seq.iter 更适合无论如何只返回“单位”的简单迭代。但请原谅我,我还在学习;)。

4

2 回答 2

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则更为合适。

于 2014-06-12T12:35:52.323 回答
1

Seq.map操作返回一个新序列,其中包含将指定函数应用于输入序列元素的结果。这意味着您应该只在需要对结果做某事时使用它。它“什么都不做”的原因是序列被懒惰地评估。这意味着使用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<_>)
于 2014-06-12T12:37:46.837 回答