10

내가이 async 워크 플로우에 Option 동안을 반환하고 싶은 말은 어쩌면 계산 식을 결합 match. 커스텀 빌더를 만들 수는 있지만 두 개의 계산식을 일반적으로 결합하는 방법이 있습니까? 그것은 다음과 같이 보일 수 있습니다F에게 # 비동기 및

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

하스켈이 "모나드 변압기"라고 부르는 것을 묻고 있습니다.이 경우 짧은 대답은 "아니오"입니다. 불행히도 그들을 결합 할 일반적인 방법은 없습니다. 하스켈에는 표준 모나드의 변압기 버전이있어 다른 사람들에게 이식 할 수 있습니다. 그러나 F #의 타입 시스템에서 이들을 정의 할 수도 있습니다. –

+0

[match !] (https://github.com/fsharp/fslang-suggestions/issues/572) ("match-bang"에서와 같이) : "let!" 그 다음에 "일치"가옵니다. 나는 잠시 동안 당신이 이야기하고있는 것을 할 무언가를 원했고, 나는 F로 구현되도록 노력하고있다. # – Jwosty

답변

11

일반적으로 일반적인 워크 플로를 사용하는 대신 F #에서는 직접 워크 플로를 정의하거나 사례 asyncmaybe처럼 사용할 수있는 워크 플로를 사용합니다. 그러나이를 사용하려면 특정 워크 플로 조합을 코딩해야합니다 손으로.

또는 당신은 모나드 변압기입니다 OptionT를 사용하여 다음 워크 플로우를 사용하고, 여기에 작업의 예입니다, 그것은 자동으로 파생 될 경우에, 모나드에 대한 일반적인 워크 플로우를 제공하는 프로젝트 인 F#+를 사용할 수 있습니다

단지 ( Option하지) Async 취급하기 때문에 단지 우리 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 

첫 번째 함수는 다른 모나드에 '해제'되도록 모두 상기 제 2 기능 상품 갖는다 DU.

두 워크 플로가 자동으로 파생된다는 것을 알 수 있듯이 (비동기 워크 플로) 및 원하는 워크 플로가 파생됩니다.

이 방법에 대한 자세한 내용은 Monad Transformers을 참조하십시오.

+1

당신은 거기에 당신의 작업을 위해 더 많은 upvotes을 가질 자격이있다. :) – Carsten

5

그렇게하는 간단한 방법은 Option module을 사용하는 것입니다

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

난 당신이 너무 자주 async의 맥락에서 option 처리하지 않는 가정합니다. FSharpx는 option 유형에 대해 더 많은 high-order functions을 제공합니다. 대부분의 경우, 나는 그것들을 사용하는 것으로 충분하다고 생각한다.

이러한 기능을 사용하는 느낌을 받으려면 nice article을 살펴보십시오.

0
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 # 계산 표현식을 사용하십시오.