Recursive iterators in F#
Tagged as F#C#’s iterator feature makes it very easy to produce sequences without having to build your own data structure — particularly handy for lazy sequences. However one common niggle is that if the iterator obtains a sequence of things it wants to include in its returned sequence, it has to explicitly traverse that sequence yielding them one at a time. A place this often turns up is when the iterator calls itself recursively, for example when traversing a hierarchy. For example, consider an iterator that gets all the files in or below a specified directory:
public static IEnumerable<string> FilesBelow(string directory) { foreach (var file in Directory.EnumerateFiles(directory)) { yield return file; } foreach (var subdir in Directory.EnumerateDirectories(directory)) { // yield return FilesBelow(subdir); // won't compile foreach (var file in FilesBelow(subdir)) { yield return file; } } }
Note the extra foreach loop over the results of the recursive call.
F# has something similar to iterators, which it calls sequence expressions. A sequence expression is introduced by the term seq, and similar to C# it uses the term yield to produce values:
seq { for n in 1 .. 10 do yield n * n } // yields 1, 4, 9 ... 81, 100
(You can use -> as a shorthand for do yield here, but I’ve spelled it out explicitly because of what’s coming next.)
Like a C# iterator, a F# sequence expression can call functions which return sequences and yield up the results. We can therefore rewrite our C# directory flattening function like this:
let rec filesBelow directory = seq { for f in Directory.EnumerateFiles(directory) do yield f for d in Directory.EnumerateDirectories(directory) do for f in (filesBelow d) do yield f }
Unlike C#, however, F# sequence expressions do have a special keyword for yielding an entire sequence. That keyword is yield!, pronounced yield-bang. yield! allows us to tighten up our recursive iterator nicely:
let rec filesBelow directory = seq { for f in Directory.EnumerateFiles(directory) do yield f for d in Directory.EnumerateDirectories(directory) do yield! (filesBelow d) }
Using yield! on the results of the recursive call allows us to avoid the noise of the extra ‘for’ expression.
One Response to “Recursive iterators in F#”
Leave a Reply
Categories
BrainDump (1)
Community Code (4)
Events (16)
F# (14)
General (53)
Lab Samples (2)
LightSpeed (268)
MegaPack (8)
News (71)
NHibernate Designer (26)
Nightly news (52)
Phone Elements (24)
Products (87)
Projects (5)
Screencast (6)
SharePoint (3)
Silverlight (14)
Silverlight Elements (66)
SimpleDB Management Tools (20)
Visual Studio (9)
VS File Explorer (7)
Web Workbench (39)
WPF (44)
WPF Diagrams (57)
WPF Elements (110)
WPF Property Grid (32)



Posted by Ivan Towlson on 28 February 2011 



Yeah, but its better than c# because your code will not be n^2
http://blogs.msdn.com/b/wesdyer/archive/2007/03/23/all-about-iterators.aspx