2010-11-01 7 views
9

निम्न उदाहरण जैसे कि नेस्टेड पैटर्न मिलान कैसे हो सकता है, फिर से लिखा जा सकता है ताकि None केवल एक बार निर्दिष्ट हो? मैं सोचता हूं शायद मोनड इस समस्या को हल करता है। क्या एफ # कोर लाइब्रेरी में कुछ समान है? या, क्या कोई वैकल्पिक दृष्टिकोण है?नेस्टेड पैटर्न मिलान से बचने (संभावित रूप से शायद मोनैड के साथ)

match a with 
| Some b -> 
    let c = b.SomeProperty 
    match c with 
    | Some d -> 
     let e = d.SomeProperty 
     //and so on... 
    | None ->() 
| None ->() 

उत्तर

12

आप इस का उपयोग कर निर्मित क्षमताओं का समाधान कर सकते हैं: Option.bind

type A = 
    member this.X : B option = Unchecked.defaultof<_> 
and B = 
    member this.Y : С option = Unchecked.defaultof<_> 
and С = 
    member this.Z : string option = Unchecked.defaultof<_> 


let a : A = Unchecked.defaultof<_> 
let v = 
    match 
     a.X 
     |> Option.bind (fun v -> v.Y) 
     |> Option.bind (fun v -> v.Z) with 
    | Some s -> s 
    | None -> "<none>" 

सच कहूं, मुझे शक है कि पूर्ण विकसित 'हो सकता है' कार्यान्वयन शुरू करने (संगणना भाव के माध्यम से) यहाँ छोटा कर सकते हैं कोड।

संपादित: सपना मोड - पर

मुझे लगता है कि Option.bind संस्करण के साथ करता है, तो एफ # विशेष मामले के लिए और अधिक हल्के वाक्यविन्यास है छोटा बनाया जा सकता है: लैम्ब्डा है कि इसके तर्क के कुछ सदस्य को देखें :

"123" |> fun s -> s.Length // current version 
"123" |> #.Length // hypothetical syntax 

यह कैसे नमूना पहले से ही इस तरह के क्षमता है कि Nemerle में फिर से लिखा जा सकता है:

using System; 
using Nemerle.Utility; // for Accessor macro : generates property for given field 

variant Option[T] 
{ 
    | Some {value : T} 
    | None 
} 

module OptionExtensions 
{ 
    public Bind[T, U](this o : Option[T], f : T -> Option[U]) : Option[U] 
    { 
     match(o) 
     { 
      | Option.Some(value) => f(value) 
      | Option.None => Option.None() 
     } 
    } 
} 

[Record] // Record macro: checks existing fields and creates constructor for its initialization 
class A 
{ 
    [Accessor] 
    value : Option[A]; 
} 

def print(_) 
{ 
    // shortened syntax for functions with body -> match over arguments 
    | Option.Some(_) => Console.WriteLine("value"); 
    | Option.None => Console.WriteLine("none"); 
} 

def x = A(Option.Some(A(Option.Some(A(Option.None()))))); 
print(x.Value.Bind(_.Value)); // "value" 
print(x.Value.Bind(_.Value).Bind(_.Value)); // "none" 
+0

मुझे उत्सुकता है कि यदि आप मिलान प्रकार विभिन्न प्रकारों पर संचालित होते हैं, उदाहरण के लिए बाहरी विकल्प और आंतरिक सूची ... संपूर्ण अभिव्यक्ति अभी भी एक विकल्प लौट रही है। – Daniel

+0

क्या आप काल्पनिक नमूना दे सकते हैं: स्रोत कोड और परिणामस्वरूप आप क्या प्राप्त करना चाहते हैं? – desco

1

मैं इस सुझाव है कि नहीं है, लेकिन आप भी अपवाद हैंडलिंग के साथ इसे हल कर सकते हैं:

try 
    <code that just keeps dotting into option.Value with impunity> 
with 
    | :? System.NullReferenceException -> "None" 

मैं सिर्फ अपवाद हैंडलिंग संभवत:/या तो monads या Option.bind के किसी न किसी तुल्यता का कहना चाहते थे। आम तौर पर उनमें से एक को अपवाद फेंकने और पकड़ने के लिए पसंद करते हैं।

+0

मेरा उदाहरण थोड़ा सीमित है। मैं यह भी जानना चाहूंगा कि अधिक सामान्य मामला कैसे हल किया जा सकता है, यानी, नेस्टेड मिलान जहां प्रकार सभी 'विकल्प' नहीं हैं। – Daniel

+0

मैं समझ नहीं पा रहा हूं कि आप सामान्य मामले के बाद क्या कर रहे हैं; शायद आप एक नए प्रश्न में एक उदाहरण पोस्ट कर सकते हैं। – Brian

+0

आप इसे मोनैड संस्करण में इंटरमीक्सिंग करके और चलो के विभिन्न हस्ताक्षर करके कर सकते हैं! (मानते हैं कि उन्हें असंबद्ध किया जा सकता है)। – TechNeilogy

5

मुझे डेस्को का जवाब पसंद है; किसी को हमेशा अंतर्निर्मित संरचनाओं का पक्ष लेना चाहिए। लेकिन Fwiw, यहाँ क्या एक कार्यप्रवाह संस्करण की तरह लग सकता है (अगर मैं समस्या सही ढंग से समझ) है:

type CE() = 

    member this.Bind (v,f) = 
    match v with 
     | Some(x) -> f x 
     | None -> None 

    member this.Return v = v 


type A (p:A option) = 

    member this.P 
    with get() = p 


let f (aIn:A option) = CE() { 
    let! a = aIn 
    let! b = a.P 
    let! c = b.P 
    return c.P } 

let x = f (Some(A(None))) 

let y = f (Some(A(Some(A(Some(A(Some(A(None))))))))) 

printfn "Your breakpoint here." 
+5

दरअसल, आप अपने सीई प्रकार में उल्लिखित निर्माण-निर्माण का उपयोग कर सकते हैं। बस इस तरह के सदस्य की तरह। बाइंड (वी, एफ) = Option.bind f v' –

0

FSharpx से Option.maybe का उपयोग करना:

open FSharpx 
type Pet = { Name: string; PreviousOwner: option<string> } 
type Person = { Name: string; Pet: option<Pet> } 

let pers = { Name = "Bob"; Pet = Some {Name = "Mr Burns"; PreviousOwner = Some "Susan"} } 

Option.maybe { 
    let! pet = pers.Pet 
    let! prevOwner = pet.PreviousOwner 
    do printfn "%s was the previous owner of %s." prevOwner pet.Name 
} 

आउटपुट:

Susan was the previous owner of Mr Burns. 

लेकिन, जैसे इस व्यक्ति के साथ इसके बजाय कोई आउटपुट नहीं है:

let pers = { Name = "Bob"; Pet = None } 
संबंधित मुद्दे