I am new to functional programming in general and started learning F# recently. I wanted to use an async workflow returning Async<'U option>
to pick an item in a Sequence. I find a nice Seq.pick
function, but I am not sure how I could use that with an async workflow.
If that is not possible, is there another alternative to using an imperative style program to pick the item from the list. The following is a modified variation of my program. Any feedback is highly appreciated.
let run = async {
while not stopped do
use! resource = acquireResourceLockAsync
let! items = fetchItemsAsync 5
let! item = Seq.pick returnIfLocked items
let! status = performTaskAsync item
do! updateStatusAsync status
do! Async.Sleep 1000
}
Thanks in anticipation.
EDIT: Updated my question based on the answer by jpalmer. I noticed both Seq.filter
and Seq.pick
earlier and decided that Seq.pick
will meet my need better, as I need the first item that I am able to lock. However, I forgot to change the return value of my function - instead of returning true
, it should return Some(item)
. Now with that update, is there an elegant way to approach this without 1) blocking a thread to convert Async<'U option>
to 'U
and 2) resorting to an imperative style looping?
I am unclear exactly what you are trying to do. If you want to convert from Async<'T>
to 'T
non-blocking, then you want to use let!
in an async workflow. So the seq-like logic probably needs to be written as its own loop, as suggested below. If that doesn't help, then perhaps share more code, especially the intended types of items/item/returnIfLocked, as I'm unclear what's async in your example.
let asyncPick f (s:seq<_>) =
async {
use e = s.GetEnumerator()
let r = ref None
while Option.isNone(!r) && e.MoveNext() do
let! x = f e.Current
r := x
match !r with
| Some z -> return z
| None -> return failwith "no matching item found"
}
let chooser ax =
async {
let! x = ax
if x%3 = 0 then
return Some x
else
return None
}
let s = seq { for i in 1..10 do yield async { return i } }
let main() =
async {
let! firstChosen = s |> asyncPick chooser
return firstChosen
}
|> Async.RunSynchronously
|> printfn "%d"
main()