簡體   English   中英

F#收益! operator - 實現和可能的C#等價物

[英]F# yield! operator - Implementation and possible C# equivalents

我正在學習F#,我真的很喜歡yield! (yield-bang)運營商。 不僅因為它的名字,而且它當然也是它的作用。

yield! operator基本上允許您從序列表達式中生成序列的所有元素。 這對於編寫枚舉器很有用。 由於我經常遇到大而復雜的調查員,我對策略很感興趣,我們可以用它來分解它們,並從簡單的枚舉器中編寫它們。

不幸的是, yield! 運算符在C#中不可用。 據我所知,它的作用就像foreach (var x in source) yield x; 但是我正在閱讀的這本書( Petricek的真實世界F# - 曼寧 )表明它有更好的表現......

  • 那么F#編譯器到底在做什么呢? (是的,我也可以使用Reflector來查看它,但我希望對機制有更詳細的描述)。

為了在C#中實現類似的構造,我已經探索了多種方法,但它們都沒有像yield!一樣簡潔yield! 操作員,我也不確定它們的復雜性。 如果我的BigO號碼正確,有人可以提供輸入嗎?

  • 將枚舉器分解為多個私有枚舉器,然后從公共枚舉器中生成每個元素:

     foreach (var x in part1()) yield x foreach (var x in part2()) yield x 

    這將有效地導致每個元素的“雙倍收益”。 那是O(2n)嗎? (或者可能更糟?)無論如何,使用這種方法阻止我使用yield break; 來自我的任何子部分。

  • 將枚舉器分解為多個私有枚舉器,然后從公共枚舉器中連接所有私有枚舉器:

     return part1().Concat(part2()) 

    我相信這與上述解決方案沒有什么不同,因為Concat()是按照我上面概述的方式實現的。

還有其他選擇嗎?

在當前版本的C#中,我認為除了foreach... yield return之外你還有其他選擇foreach... yield returnConcat 我同意yield!會很高興yield! C#中的運算符,它會使某些結構更加優雅,但我懷疑這個功能是否會成為“必備”列表,因為我們可以很容易地將其刪除。

您可能對此MS研究論文感興趣,該論文介紹了一種新的yield foreach構造:

IEnumerable<XmlNode> Traverse(XmlNode n)
{
    yield return n;
    foreach (XmlNode c in n.ChildNodes)
        yield foreach Traverse(c);
}

關於復雜性的問題:在兩種情況下都是O(n) 不使用O(2n) ,因為它表示與O(n) (線性)相同的復雜度。 我認為你不能用當前的C#功能做得更好......

關於編譯器如何轉換yield! 操作,Thomas Levesque在他的回答中引用的論文說明了4.3節中的一種實現技術(特別是,他們的示例跨越圖7-9說明了一般策略)。 我不認為在C#中的迭代器塊中有任何好方法可以做到這一點 - 因為我理解你提出的解決方案,它們在遞歸使用時都會導致二次行為。 您總是可以手動創建NestedEnumerable<T>子類來實現性能優勢,但與使用普通迭代器塊相比,這將非常難看。

yield!沒有直接的對應物yield! 在C#中。 你現在仍然堅持使用foreachyield return

但是,IIRC,LINQ提供類似的東西,即SelectMany查詢運算符,它將C#轉換為from .. in ..子句中的多個。

(我希望我不會混淆兩個不同的概念,但是IIRC,兩者都yield!SelectMany基本上是“扁平化”投影;即,對象的層次結構被“扁平化”為一個列表。)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM