2014-06-12 55 views
0

今天我有一個問題在一個郵箱處理器的迭代中實現一些簡單的處理。在一個MailboxProcessor,Seq.map和Seq.iter內迭代處理

起初我試着用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更適合簡單的迭代,只是返回'單位'。但請原諒我,我仍在學習;)。

回答

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

這是有道理的,因爲'Seq.map'設計投入和產出;爲什麼在你需要它們之前產生結果,特別是如果你從不這樣做?而'Seq.iter'採用了一種返回單元的方法,所有這些都是關於副作用的。 –

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<_>)