10

decir que quiero devolver un Option mientras que en un async flujo de trabajo:Combinar F # asíncrono y tal vez la expresión de cálculo

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

Lo ideal sería utilizar la expresión de cálculo tal vez de FSharpx al mismo tiempo que asíncrono para evitar hacer el match. Podría hacer un generador personalizado, pero ¿hay alguna manera de combinar genéricamente dos expresiones de cálculo? Puede parecer algo como esto:

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

Creo que estás pidiendo lo que Haskell llama "transformadores de mónada", en cuyo caso la respuesta corta es "no". No hay una forma genérica de combinarlos, desafortunadamente. En Haskell hay una versión de transformador de cada mónada estándar que luego puede injertar en otras, pero no estoy seguro de que sea posible definirlas en el sistema de tipos de F # ... –

+0

Puede que le interese una característica propuesta aprobada llamada [coincidencia !] (https://github.com/fsharp/fslang-suggestions/issues/572) (como en "match-bang"): es un "let!" seguido de un "partido". He querido algo de lo que estás hablando hace un tiempo, y he estado trabajando para que se implemente en F # – Jwosty

Respuesta

11

Típicamente en F # en lugar de utilizar los flujos de trabajo genéricos se define el flujo de trabajo a mano, o utilizar uno que está listo a disposición como en su caso async y maybe pero si desea utilizarlos en combinación tendrá que codificar una combinación específica de flujo de trabajo a mano.

Alternativamente, puede utilizar F#+ que es un proyecto que proporciona flujos de trabajo genéricos de mónadas, en ese caso se deriva automáticamente para usted, aquí hay un ejemplo de trabajo, utilizando el flujo de trabajo y luego usando OptionT que es un transformador mónada:

#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 

la primera función tiene que ser 'levantado' en la otra mónada, ya que sólo se ocupa de Async (no con Option), el segundo se ocupa de funciones con tanto por lo que sólo necesita ser 'lleno' en nuestro OptionT DU.

Como puede ver, ambos flujos de trabajo se derivan automáticamente, el que tenía (el flujo de trabajo asincrónico) y el que desea.

Para obtener más información sobre este enfoque, lea acerca de Monad Transformers.

+1

mereces más votos por tu trabajo allí :) – Carsten

5

Una forma sencilla de hacerlo es utilizar Option module:

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

supongo que no tiene que hacer frente a option en el contexto de async tan a menudo. FSharpx también proporciona muchos más high-order functions para el tipo option. La mayoría de los casos, creo que usarlos es suficiente.

Para tener la sensación de utilizar estas funciones, consulte este 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 
    } 
} 

simplemente use f # Expresiones de cálculo dentro.

Cuestiones relacionadas