10

कहते हैं कि मैं एक async कार्यप्रवाह में एक Option जबकि लौटना चाहते कम्बाइन match। मैं एक कस्टम बिल्डर बना सकता हूं, लेकिन क्या सामान्य रूप से दो गणना अभिव्यक्तियों को गठबंधन करने का कोई तरीका है? यह कुछ इस तरह दिख सकता है:एफ # async और शायद गणना अभिव्यक्ति

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) (जैसा कि "मैच-बैंग" में है): यह एक "चलो!" है एक "मैच" के बाद। मैं कुछ ऐसा करना चाहता था जो आप थोड़ी देर के लिए बात कर रहे हैं, और मैं इसे एफ # – Jwosty

उत्तर

11

आमतौर पर एफ # में के बजाय सामान्य वर्कफ़्लो का उपयोग कर आप हाथ से कार्यप्रवाह निर्धारित करें, या एक है कि तैयार उपलब्ध है अपने मामले async और maybe में के रूप में उपयोग लेकिन आप एक विशिष्ट कार्यप्रवाह संयोजन कोड करने के लिए की आवश्यकता होगी आप उन्हें संयुक्त उपयोग करना चाहते हैं हाथ से।

वैकल्पिक रूप से आप अपने कार्यप्रवाह का उपयोग कर और फिर OptionT जो एक इकाई ट्रांसफार्मर का उपयोग कर F#+ उपयोग कर सकते हैं जो एक परियोजना है कि, monads के लिए सामान्य कार्य प्रवाह प्रदान करता है कि इस मामले में यह अपने आप आपके लिए प्राप्त किया जा जाएगा में है, यहाँ एक काम उदाहरण है,:

#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 में 'पैक' किए जाने की आवश्यकता है, ड्यू।

जैसा कि आप देख सकते हैं कि वर्कफ़्लो स्वचालित रूप से व्युत्पन्न होते हैं, आपके पास एक था (async वर्कफ़्लो) और जिसे आप चाहते हैं।

इस दृष्टिकोण के बारे में अधिक जानकारी के लिए Monad Transformers पर पढ़ें।

+1

में लागू करने पर काम कर रहा हूं, आप अपने काम के लिए और अधिक उत्साह के लायक हैं :) – Carsten

5

ऐसा करने के लिए एक आसान तरीका Option module उपयोग करने के लिए है:

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

मुझे लगता है कि आप इतनी बार async के संदर्भ में option से निपटने के लिए नहीं है। एफएसएचआरएक्स 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 # गणना अभिव्यक्तियों का उपयोग करें।