18

ワークフローOptionでしばらく戻りたいとしましょう:async

let run = 
    async {
        let! x = doAsyncThing
        let! y = doNextAsyncThing x
        match y with
        | None -> return None
        | Some z -> return Some <| f z
    }

理想的には、非同期を実行することを避けるために、非同期と同時にFSharpxからの多分計算式を使用しmatchます。カスタムビルダーを作成することはできますが、2つの計算式を一般的に組み合わせる方法はありますか?次のようになります。

let run = 
    async {
        let! x = doAsyncThing
        let! y = doNextAsyncThing x
        return! f y
    }
4

3 に答える 3

22

通常、F#では、一般的なワークフローを使用する代わりに、ワークフローを手動で定義するか、ケースのようにすぐに使用できるワークフローを使用しますが、それらasyncmaybe組み合わせて使用​​する場合は、特定のワークフローの組み合わせを手動でコーディングする必要があります。

または、モナドの一般的なワークフローを提供するプロジェクトであるF#+を使用することもできます。その場合、自動的に派生します。ワークフローを使用OptionTして、モナド変換子を使用する実際の例を次に示します。

#r "nuget: FSharpPlus, 1.2"

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(を処理しないため)、2番目の関数は両方を処理するため、 DUOptionに「パック」するだけで済みます。OptionT

ご覧のとおり、両方のワークフローが自動的に導出されます。つまり、使用していたワークフロー(非同期ワークフロー)と必要なワークフローです。

このアプローチの詳細については、モナド変換子についてお読みください。

于 2015-10-05T16:24:11.870 に答える
7

これを行う簡単な方法は、オプションモジュールを使用することです。

let run = 
    async {
        let! x = doAsyncThing
        let! y = doNextAsyncThing x
        return Option.map f y
    }

私はあなたがそれほど頻繁optionに文脈で対処する必要はないと思います。asyncFSharpxは、型に対してさらに多くの高階関数optionも提供します。ほとんどの場合、それらを使用するだけで十分だと思います。

これらの機能の使い方を実感していただくために、こちらの素敵な記事をご覧ください。

于 2012-09-11T19:55:32.173 に答える
2
type MaybeMonad() = 
    member __.Bind(x, f) = 
        match x with
        | Some v -> f v
        | None -> None
    member __.Return(x) = 
        Some x

let maybe = MaybeMonad()

let run = async {
    let! x = doAsyncThing
    let! y = doNextAsyncThing x
    return maybe {
        let! y_val = y
        return f y_val
    }
}

内部でf#計算式を使用するだけです。

于 2017-03-29T09:21:34.360 に答える