खोज…
प्रकारों का परिचय
प्रकार विभिन्न प्रकार की चीजों का प्रतिनिधित्व कर सकते हैं। यह एक एकल डेटा, डेटा का एक समूह या एक फ़ंक्शन हो सकता है।
F # में, हम प्रकारों को दो श्रेणियों में बाँट सकते हैं।
एफ # प्रकार:
// Functions let a = fun c -> c // Tuples let b = (0, "Foo") // Unit type let c = ignore // Records type r = { Name : string; Age : int } let d = { Name = "Foo"; Age = 10 } // Discriminated Unions type du = | Foo | Bar let e = Bar // List and seq let f = [ 0..10 ] let g = seq { 0..10 } // Aliases type MyAlias = string
.NET प्रकार
- अंतर्निहित प्रकार (इंट, बूल, स्ट्रिंग, ...)
- कक्षाएं, संरचनाएं और इंटरफेस
- प्रतिनिधियों
- Arrays
संकेतन टाइप करें
टाइप संक्षेपाक्षर आपको मौजूदा प्रकारों पर उपनाम बनाने की अनुमति देते हैं ताकि वे अधिक सार्थक इंद्रियां दे सकें।
// Name is an alias for a string
type Name = string
// PhoneNumber is an alias for a string
type PhoneNumber = string
फिर आप अन्य प्रकार से भी उपनाम का उपयोग कर सकते हैं:
// Create a record type with the alias
type Contact = {
Name : Name
Phone : PhoneNumber }
// Create a record instance
// We can assign a string since Name and PhoneNumber are just aliases on string type
let c = {
Name = "Foo"
Phone = "00 000 000" }
printfn "%A" c
// Output
// {Name = "Foo";
// Phone = "00 000 000";}
सावधान रहें, उपनाम प्रकार की स्थिरता के लिए जांच नहीं करते हैं। इसका मतलब यह है कि दो उपनाम जो समान प्रकार को लक्षित करते हैं, उन्हें एक दूसरे को सौंपा जा सकता है:
let c = {
Name = "Foo"
Phone = "00 000 000" }
let d = {
Name = c.Phone
Phone = c.Name }
printfn "%A" d
// Output
// {Name = "00 000 000";
// Phone = "Foo";}
प्रकार # कीवर्ड का उपयोग करके एफ में बनाए जाते हैं
F#
विभिन्न प्रकार के प्रकार बनाने के लिए type
कीवर्ड का उपयोग करता है।
- उपनाम लिखें
- भेदभावपूर्ण संघ प्रकार
- रिकॉर्ड प्रकार
- इंटरफ़ेस प्रकार
- वर्ग प्रकार
- संरचना प्रकार
समतुल्य C#
कोड वाले उदाहरण जहां संभव हो:
// Equivalent C#:
// using IntAliasType = System.Int32;
type IntAliasType = int // As in C# this doesn't create a new type, merely an alias
type DiscriminatedUnionType =
| FirstCase
| SecondCase of int*string
member x.SomeProperty = // We can add members to DU:s
match x with
| FirstCase -> 0
| SecondCase (i, _) -> i
type RecordType =
{
Id : int
Name : string
}
static member New id name : RecordType = // We can add members to records
{ Id = id; Name = name } // { ... } syntax used to create records
// Equivalent C#:
// interface InterfaceType
// {
// int Id { get; }
// string Name { get; }
// int Increment (int i);
// }
type InterfaceType =
interface // In order to create an interface type, can also use [<Interface>] attribute
abstract member Id : int
abstract member Name : string
abstract member Increment : int -> int
end
// Equivalent C#:
// class ClassType : InterfaceType
// {
// static int increment (int i)
// {
// return i + 1;
// }
//
// public ClassType (int id, string name)
// {
// Id = id ;
// Name = name ;
// }
//
// public int Id { get; private set; }
// public string Name { get; private set; }
// public int Increment (int i)
// {
// return increment (i);
// }
// }
type ClassType (id : int, name : string) = // a class type requires a primary constructor
let increment i = i + 1 // Private helper functions
interface InterfaceType with // Implements InterfaceType
member x.Id = id
member x.Name = name
member x.Increment i = increment i
// Equivalent C#:
// class SubClassType : ClassType
// {
// public SubClassType (int id, string name) : base(id, name)
// {
// }
// }
type SubClassType (id : int, name : string) =
inherit ClassType (id, name) // Inherits ClassType
// Equivalent C#:
// struct StructType
// {
// public StructType (int id)
// {
// Id = id;
// }
//
// public int Id { get; private set; }
// }
type StructType (id : int) =
struct // In order create a struct type, can also use [<Struct>] attribute
member x.Id = id
end
प्रकार का आविष्कार
स्वीकृति
इस उदाहरण को टाइप इंट्रेंस पर इस लेख से अनुकूलित किया गया है
टाइप इंफ़ेक्शन क्या है?
टाइप इनवेंशन वह तंत्र है जो कंपाइलर को यह बताने की अनुमति देता है कि किस प्रकार का उपयोग किया जाता है और कहां। यह तंत्र एक एल्गोरिथ्म पर आधारित है जिसे अक्सर "हिंडले-मिलनर" या "एचएम" कहा जाता है। सरल और फ़ंक्शन मानों के प्रकारों को निर्धारित करने के लिए कुछ नियमों के नीचे देखें:
- शाब्दिक रूप से देखें
- कुछ कार्यों और अन्य मूल्यों के साथ बातचीत करें
- किसी भी स्पष्ट प्रकार की बाधाओं को देखें
- यदि कहीं भी कोई बाधा नहीं है, तो स्वचालित रूप से सामान्य प्रकारों के लिए सामान्यीकरण करें
शाब्दिक रूप से देखें
कंपाइलर शाब्दिक रूप से देखकर कटौती कर सकता है। यदि शाब्दिक एक int है और आप इसमें "x" जोड़ रहे हैं, तो "x" को भी int होना चाहिए। लेकिन अगर शाब्दिक एक फ्लोट है और आप इसमें "x" जोड़ रहे हैं, तो "x" भी एक फ्लोट होना चाहिए।
यहाँ कुछ उदाहरण हैं:
let inferInt x = x + 1
let inferFloat x = x + 1.0
let inferDecimal x = x + 1m // m suffix means decimal
let inferSByte x = x + 1y // y suffix means signed byte
let inferChar x = x + 'a' // a char
let inferString x = x + "my string"
फ़ंक्शंस और अन्य मूल्यों को देखें जिनके साथ यह इंटरैक्ट करता है
यदि कहीं भी शाब्दिक नहीं हैं, तो संकलक उन कार्यों और अन्य मूल्यों का विश्लेषण करके प्रकारों को बाहर निकालने की कोशिश करता है जिनके साथ वे बातचीत करते हैं।
let inferInt x = x + 1
let inferIndirectInt x = inferInt x //deduce that x is an int
let inferFloat x = x + 1.0
let inferIndirectFloat x = inferFloat x //deduce that x is a float
let x = 1
let y = x //deduce that y is also an int
किसी भी स्पष्ट प्रकार की बाधाओं या टिप्पणियों को देखें
यदि कोई स्पष्ट प्रकार की बाधाएं या एनोटेशन निर्दिष्ट हैं, तो कंपाइलर उनका उपयोग करेगा।
let inferInt2 (x:int) = x // Take int as parameter
let inferIndirectInt2 x = inferInt2 x // Deduce from previous that x is int
let inferFloat2 (x:float) = x // Take float as parameter
let inferIndirectFloat2 x = inferFloat2 x // Deduce from previous that x is float
स्वचालित सामान्यीकरण
यदि इस सब के बाद, कोई अड़चन नहीं पाई जाती है, तो कंपाइलर केवल प्रकार को सामान्य बनाता है।
let inferGeneric x = x
let inferIndirectGeneric x = inferGeneric x
let inferIndirectGenericAgain x = (inferIndirectGeneric x).ToString()
चीजें जो टाइप इंट्रेंस के साथ गलत हो सकती हैं
प्रकार का अनुमान सही नहीं है, अफसोस। कभी-कभी कंपाइलर के पास कोई सुराग नहीं होता कि वह क्या करे। फिर, यह समझना कि क्या हो रहा है, वास्तव में संकलक को मारने की इच्छा के बजाय शांत रहने में मदद करेगा। टाइप त्रुटियों के कुछ मुख्य कारण इस प्रकार हैं:
- आदेश से घोषणा
- ज्यादा जानकारी नहीं है
- ओवरलोड तरीके
आदेश से घोषणा
एक बुनियादी नियम यह है कि उपयोग किए जाने से पहले आपको कार्यों की घोषणा करनी चाहिए।
यह कोड विफल रहता है:
let square2 x = square x // fails: square not defined
let square x = x * x
लेकिन यह ठीक है:
let square x = x * x
let square2 x = square x // square already defined earlier
पुनरावर्ती या एक साथ घोषणाएं
"आउट ऑफ ऑर्डर" समस्या का एक प्रकार पुनरावर्ती कार्यों या परिभाषाओं के साथ होता है जिन्हें एक-दूसरे को संदर्भित करना होता है। इस मामले में किसी भी प्रकार की पुनरावृत्ति मदद नहीं करेगी - हमें कंपाइलर की सहायता के लिए अतिरिक्त कीवर्ड का उपयोग करने की आवश्यकता है।
जब कोई फ़ंक्शन संकलित किया जा रहा है, तो फ़ंक्शन पहचानकर्ता शरीर के लिए उपलब्ध नहीं है। इसलिए यदि आप एक सरल पुनरावर्ती कार्य को परिभाषित करते हैं, तो आपको एक कंपाइलर त्रुटि मिलेगी। फ़ंक्शन फ़ंक्शन के हिस्से के रूप में "rec" कीवर्ड को जोड़ना है। उदाहरण के लिए:
// the compiler does not know what "fib" means
let fib n =
if n <= 2 then 1
else fib (n - 1) + fib (n - 2)
// error FS0039: The value or constructor 'fib' is not defined
यहाँ बताया गया है कि "rec fib" के साथ तय किया गया संस्करण पुनरावर्ती है:
let rec fib n = // LET REC rather than LET
if n <= 2 then 1
else fib (n - 1) + fib (n - 2)
ज्यादा जानकारी नहीं है
कभी-कभी, कंपाइलर के पास एक प्रकार निर्धारित करने के लिए पर्याप्त जानकारी नहीं होती है। निम्नलिखित उदाहरण में, संकलक को पता नहीं है कि लंबाई विधि किस प्रकार पर काम करने वाली है। लेकिन यह इसे सामान्य नहीं बना सकता है, इसलिए यह शिकायत करता है।
let stringLength s = s.Length
// error FS0072: Lookup on object of indeterminate type
// based on information prior to this program point.
// A type annotation may be needed ...
इस प्रकार की त्रुटि स्पष्ट एनोटेशन के साथ तय की जा सकती है।
let stringLength (s:string) = s.Length
ओवरलोड तरीके
.NET में एक बाहरी वर्ग या विधि को कॉल करते समय, आपको अक्सर ओवरलोडिंग के कारण त्रुटियां मिलेंगी।
कई मामलों में, जैसे नीचे का संक्षिप्त उदाहरण, आपको बाहरी फ़ंक्शन के मापदंडों को स्पष्ट रूप से एनोटेट करना होगा, ताकि कंपाइलर को पता हो कि कॉल करने के लिए कौन सी अधिभार विधि है।
let concat x = System.String.Concat(x) //fails
let concat (x:string) = System.String.Concat(x) //works
let concat x = System.String.Concat(x:string) //works
कभी-कभी अतिभारित तरीकों में अलग-अलग तर्क नाम होते हैं, जिस स्थिति में आप संकलक को तर्कों का नाम देकर एक सुराग भी दे सकते हैं। यहाँ StreamReader निर्माता के लिए एक उदाहरण है।
let makeStreamReader x = new System.IO.StreamReader(x) //fails
let makeStreamReader x = new System.IO.StreamReader(path=x) //works