Ответ 1
Обычно в F # вместо использования общих рабочих процессов вы определяете рабочий процесс вручную или используете тот, который готов, как в вашем случае async
и maybe
, но если вы хотите использовать их вместе, вам нужно будет закодировать специфическая комбинация рабочего процесса вручную.
В качестве альтернативы вы можете использовать F # +, который является проектом, который предоставляет общие рабочие процессы для монад, и в этом случае он будет автоматически получен для вы, здесь рабочий пример, используя ваш рабочий процесс, а затем используя OptionT
, который является монадным трансформатором:
#nowarn "3186"
#r @"FSharpPlus.dll"
open FSharpPlus
open FSharpPlus.Data
let doAsyncThing = async {return System.DateTime.Now}
let doNextAsyncThing (x:System.DateTime) = async {
let m = x.Millisecond
return (if m < 500 then Some m else None)}
let f x = 2 * x
// then you can use Async<_> (same as your code)
let run = monad {
let! x = doAsyncThing
let! y = doNextAsyncThing x
match y with
| None -> return None
| Some z -> return Some <| f z}
let res = Async.RunSynchronously run
// or you can use OptionT<Async<_>> (monad transformer)
let run' = monad {
let! x = lift doAsyncThing
let! y = OptionT (doNextAsyncThing x)
return f y}
let res' = run' |> OptionT.run |> Async.RunSynchronously
Первая функция должна быть "поднята" в другую монаду, потому что она имеет дело только с async
(а не с Option
), вторая функция имеет дело с обоими, поэтому ее нужно только "упаковать" в нашу OptionT
DU.
Как вы можете видеть, оба рабочих процесса производятся автоматически, тот, который у вас был (рабочий процесс async) и тот, который вы хотите.
Для получения дополнительной информации об этом подходе прочитайте Monad Transformers.