खोज…
विकल्प की परिभाषा
एक Option
एक भेदभावपूर्ण संघ है जिसमें दो मामले हैं, None
या Some
None
।
type Option<'T> = Some of 'T | None
शून्य मानों पर विकल्प <'T> का उपयोग करें
कार्यात्मक प्रोग्रामिंग भाषाओं में F#
null
मानों को संभावित रूप से हानिकारक और खराब शैली (गैर-मुहावरेदार) माना जाता है।
इस C#
कोड पर विचार करें:
string x = SomeFunction ();
int l = x.Length;
यदि x
null
है तो x.Length
फेंक देंगे सुरक्षा जोड़ें:
string x = SomeFunction ();
int l = x != null ? x.Length : 0;
या:
string x = SomeFunction () ?? "";
int l = x.Length;
या:
string x = SomeFunction ();
int l = x?.Length;
मुहावरेदार F#
null
मानों का उपयोग नहीं किया जाता है इसलिए हमारा कोड इस तरह दिखता है:
let x = SomeFunction ()
let l = x.Length
हालांकि, कभी-कभी खाली या अमान्य मूल्यों का प्रतिनिधित्व करने की आवश्यकता होती है। तब हम Option<'T>
उपयोग कर सकते हैं:
let SomeFunction () : string option = ...
SomeFunction
या तो Some
string
मान देता है या None
। हम पैटर्न मिलान का उपयोग करके string
मान निकालते हैं
let v =
match SomeFunction () with
| Some x -> x.Length
| None -> 0
इस कोड की वजह से कम नाजुक है:
string x = SomeFunction ();
int l = x.Length;
क्योंकि हम एक string option
पर Length
नहीं कह सकते। हमें पैटर्न मिलान का उपयोग करके string
मान निकालने की आवश्यकता है और ऐसा करने से हमें गारंटी दी जाती है कि string
मान उपयोग करने के लिए सुरक्षित है।
विकल्प मॉड्यूल रेलवे ओरिएंटेड प्रोग्रामिंग सक्षम बनाता है
त्रुटि से निपटने के लिए महत्वपूर्ण है, लेकिन एक गड़बड़ी में एक सुंदर एल्गोरिथ्म बना सकता है। रेलवे ओरिएंटेड प्रोग्रामिंग ( ROP
) का उपयोग एरर हैंडलिंग को एलिगेंट और कंपोजेबल बनाने में किया जाता है।
साधारण कार्य f
पर विचार करें:
let tryParse s =
let b, v = System.Int32.TryParse s
if b then Some v else None
let f (g : string option) : float option =
match g with
| None -> None
| Some s ->
match tryParse s with // Parses string to int
| None -> None
| Some v when v < 0 -> None // Checks that int is greater than 0
| Some v -> v |> float |> Some // Maps int to float
f
का उद्देश्य इनपुट string
मान (यदि Some
) को एक int
में पार्स करना है। यदि int
0
से अधिक है, तो हम इसे float
में float
। अन्य सभी मामलों में हम None
साथ जमानत None
।
हालांकि, एक अत्यंत सरल कार्य नेस्टेड match
पठनीयता में काफी कमी आती है।
ROP
देखता है कि हमारे कार्यक्रम में दो तरह के निष्पादन पथ हैं
- खुश रास्ता - अंततः
Some
मूल्य की गणना करेगा - त्रुटि पथ - अन्य सभी पथ
None
बनाता है
चूंकि त्रुटि पथ अधिक बार होते हैं इसलिए वे कोड को संभालने के लिए होते हैं। हम चाहते हैं कि खुश पथ कोड सबसे दृश्यमान कोड पथ है।
ROP
का उपयोग कर एक समान फ़ंक्शन g
इस तरह दिख सकता है:
let g (v : string option) : float option =
v
|> Option.bind tryParse // Parses string to int
|> Option.filter ((<) 0) // Checks that int is greater than 0
|> Option.map float // Maps int to float
यह बहुत कुछ दिखता है कि हम F#
में सूचियों और अनुक्रमों को कैसे संसाधित करते हैं।
एक एक को देख सकते हैं Option<'T>
एक तरह List<'T>
है कि केवल हो सकती है 0
या 1
तत्व जहां Option.bind
की तरह बर्ताव करती है List.pick
(धारणात्मक Option.bind
को नक्शे बेहतर List.collect
लेकिन List.pick
हो सकता है समझने में आसान है)।
bind
, filter
और map
एरर पाथ को हैंडल करता है और g
केवल हैप्पी पाथ कोड होता है।
सभी कार्य जो सीधे Option<_>
स्वीकार करते हैं और Option<_>
साथ सीधे स्वीकार्य हैं |>
और >>
ROP
इसलिए पठनीयता और रचनाशीलता बढ़ाता है।
C # से विकल्प प्रकारों का उपयोग करना
विकल्प प्रकारों को C # कोड से उजागर करना अच्छा नहीं है, क्योंकि C # में उन्हें संभालने का कोई तरीका नहीं है। विकल्प या तो आपके C # प्रोजेक्ट में निर्भरता के रूप में FSharp.Core
को शुरू करने के लिए हैं (जो कि आपको क्या करना है अगर आप F # लाइब्रेरी को C # से इंटरोप करने के लिए नहीं बनाया गया है) का उपभोग कर रहे हैं, या None
मान को null
बदलने के लिए None
।
प्री-एफ # 4.0
इसे करने का तरीका आपके खुद का एक रूपांतरण समारोह बनाता है:
let OptionToObject opt =
match opt with
| Some x -> x
| None -> null
मान प्रकारों के लिए आपको उन्हें बॉक्सिंग या System.Nullable
का उपयोग करना होगा।
let OptionToNullable x =
match x with
| Some i -> System.Nullable i
| None -> System.Nullable ()
एफ # 4.0
F # 4.0 में, ofObj
, toObj
, इन ofNullable
, और toNullable
जहां Option
मॉड्यूल के लिए प्रस्तुत किए गए हैं। एफ # इंटरएक्टिव में उनका उपयोग निम्नानुसार किया जा सकता है:
let l1 = [ Some 1 ; None ; Some 2]
let l2 = l1 |> List.map Option.toNullable;;
// val l1 : int option list = [Some 1; null; Some 2]
// val l2 : System.Nullable<int> list = [1; null; 2]
let l3 = l2 |> List.map Option.ofNullable;;
// val l3 : int option list = [Some 1; null; Some 2]
// Equality
l1 = l2 // fails to compile: different types
l1 = l3 // true
ध्यान दें कि None
आंतरिक रूप से null
करने के लिए संकलित करता है। हालाँकि जहाँ तक F # का सवाल है यह None
।
let lA = [Some "a"; None; Some "b"]
let lB = lA |> List.map Option.toObj
// val lA : string option list = [Some "a"; null; Some "b"]
// val lB : string list = ["a"; null; "b"]
let lC = lB |> List.map Option.ofObj
// val lC : string option list = [Some "a"; null; Some "b"]
// Equality
lA = lB // fails to compile: different types
lA = lC // true