Can't nobody tell me F# async is easy; it seems hard to me. I wanted to put together the simplest sample (but different from all the samples I've seen) so I could get a better understanding. Maybe thistle help someone else. I'm searching a file line by line to see if I can find a match. In this case there are only 4 lines in the file so I'm splitting the file into 2 chunks. Each... async... thing (after watching a long video on C# async lately and ending up hopelessly confused about when actual new threads are created I've given up guessing) gets 2 lines. In this sample, it's pretty handy how it stops looking after finding a match.
open System.IO
open System
// So we don't just print "null" to console when not found.
let OptionToStr o =
match o with
| None -> "not found"
| Some(o) -> o
// Because our line gets wrapped into an option twice (once in Seq.tryPick and again in Seq.tryFind).
let UnwrapOption o =
match o with
| None -> None
| Some(o) -> o
// Some(matching line) if the current chunk contains our id
let ChunkContains (id:string) (chunk:string seq) =
chunk
|> Seq.tryPick ( fun line ->
// Notice how it doesn't process all lines when it finds a match.
printfn "Current: %s" line
if line.Contains id then Some(line) else None )
// Skip n lines and call our search method for the current chunk
let ProcessFileChunkAsync (lines:string seq) skip (func: string seq -> string option) =
async { // Note: async is cranky. You have to format the curly braces a certain way or compiler will complain with strange error.
return lines // return keyword required.
|> Seq.skip skip
|> Seq.truncate 2
|> func // 2nd parameter applied to previous partial application of ChunkContains below.
}
[]
let main argv =
let lines = File.ReadAllLines @"c:\temp\4LinesOfTrash.txt" // one of the lines is "hi mom"
seq { 0 .. 1 }
|> Seq.map ( fun i -> let chunkFun = ChunkContains "hi" // find the line with "hi"; partial func application
ProcessFileChunkAsync lines (i * 2) chunkFun
)
|> Async.Parallel // Fork
|> Async.RunSynchronously // Join: Take the async results and wait for them to complete.
|> Seq.tryFind ( fun item -> Option.isSome item )
|> UnwrapOption
|> OptionToStr
|> printfn "Result: %A"
|> Console.ReadLine
|> ignore
0