2015-05-25 6 views
10

मैं कैसे की तरह ('a -> 'a)एफ # जेनरिक/समारोह ओवरलोडिंग वाक्य रचना

let add a b = a + b 

एक स्पष्ट प्रकार घोषणा के बिना सामान्य रूप में एक समारोह के लेबल करने के लिए पर उलझन में यह हमें

val add : a:int -> b:int -> int 

देता हूँ लेकिन हम तो तुरंत कर सकते हैं

add "Hello " "World!" 

फोन और अब ऐड का मूल्य

0 है
val add : a:string -> b:string -> string 
val it : string = "Hello World!" 

हम तो

add 2 3 // then we get 
error: This expression was expected to have type string but here has type int 

फोन अगर मैं कैसे सुनिश्चित करते हैं एक समारोह सभी प्रकार का कहना है कि समारोह (+) परिभाषित

+0

मैं कल्पना यह एक डुप्लिकेट है; अगर मुझे पहले नहीं पूछा गया तो मुझे आश्चर्य होगा। लेकिन यह समस्या का एक उत्कृष्ट स्पष्टीकरण है। – phoog

उत्तर

16

यह एफ # की कोठरी में शर्मनाक कंकाल की हुई है।

इस प्रयास करें:

> let mapPair f (x,y) = (f x, f y) 
val mapPair : f:('a -> 'b) -> x:'a * y:'a -> 'b * 'b 

पूरी तरह से सामान्य! स्पष्ट रूप से, समारोह आवेदन और tuples काम करते हैं। यह भी सामान्य

> let makeList a b = [a;b] 
val makeList : a:'a -> b:'a -> 'a list 

हममम,:

अब इस प्रयास करें। कैसे इस बारे में:

> let makeList a b = [a + b] 
val makeList : a:int -> b:int -> int list 

अहा, जैसे ही मैं वहाँ में एक (+) है के रूप में, यह int किसी कारण से हो जाता है।
के खेलते रहने दो:

> let inline makeList a b = [a + b] 
val inline makeList : 
    a: ^a -> b: ^b -> ^c list 
    when (^a or ^b) : (static member (+) : ^a * ^b -> ^c) 

हममम, दिलचस्प। बाहर निकलता है, अगर मैं inline फ़ंक्शन करता हूं, तो F # इसे सामान्य मानता है, लेकिन यह इसे अजीब when खंड भी देता है, और मेरे सामान्य पैरामीटर में सामान्य टिक के बजाय यह अजीब ^ प्रतीक है।
इस अजीब वाक्यविन्यास को "स्थिर रूप से हल किए गए प्रकार पैरामीटर" कहा जाता है (कुछ हद तक सुसंगत स्पष्टीकरण के लिए here देखें), और मूल विचार यह है कि फ़ंक्शन (+) को इसके तर्कों को static member (+) परिभाषित करने की आवश्यकता है।आइए सत्यापित करते हैं:

> let x = 0 :> obj 
    let y = 0 :> obj 
    let z = x + y 
Script1.fsx(14,13): error FS0001: The type 'obj' does not support the operator '+' 

> type My() = 
    static member (+)(a:My, b:My) = My() 
    let x = My() 
    let y = My() 
    let z = x + y 
val x : My 
val y : My 
val z : My 

अब, इस के साथ समस्या यह है कि CLR तो एफ # गया है इस सामान्य मापदंडों के प्रकार का समर्थन नहीं करता (यानी "किसी भी प्रकार, जब तक कि यह इस तरह के और इस तरह के सदस्य हैं"), है नकली इसे संकलित समय पर इन कॉलों को हल करें और हल करें। लेकिन इसके कारण, इस सुविधा का उपयोग करने वाली किसी भी विधि को वास्तविक जेनेरिक आईएल विधियों में संकलित नहीं किया जा सकता है, और इस प्रकार मोनोमोर्फिफाइड होना चाहिए (जिसे inline द्वारा सक्षम किया गया है)।

लेकिन फिर भी, यह आवश्यकता के लिए बहुत असुविधाजनक हो सकता है कि हर कार्य अंकगणितीय ऑपरेटर inline घोषित किया जाना का उपयोग करता है, ऐसा नहीं है? तो एफ # अभी तक एक और अतिरिक्त कदम चला गया है और इन आंकड़ों को बाद में हल किए जाने के आधार पर इन स्थिर रूप से हल किए गए जेनेरिक पैरामीटर को ठीक करने का प्रयास करता है। यही कारण है कि जैसे ही आप इसे string के साथ उपयोग करते हैं, आपका कार्य string->string->string में बदल जाता है।

लेकिन अगर आप अपने कार्य inline निशान, एफ # मापदंडों ठीक करने के लिए है, क्योंकि यह समारोह आईएल के लिए नीचे संकलित करने के लिए नहीं होगा नहीं होगा, और इसलिए अपने मानकों को बरकरार रहेगा:

> let inline add a b = a + b 
val inline add : 
    a: ^a -> b: ^b -> ^c 
     when (^a or ^b) : (static member (+) : ^a * ^b -> ^c) 
+0

"यह कोठरी में एफ # के शर्मनाक कंकाल है।" -- एकमात्र? – phoog

+0

मुझे यकीन है कि कई हैं, लेकिन मुझे अपने सिर के ऊपर से कोई भी याद नहीं है। –

2

अगर मैं तुम्हें सही ढंग से समझ है पर काम करता है कि, इनलाइन का उपयोग करें:

let inline add a b = a + b 

add 2 3 |> printfn "%A" 
add "Hello " "World!" |> printfn "%A" 

प्रिंट:

5 
"Hello World!" 

लिंक: http://ideone.com/awsYNI

2

यह inline

let inline add a b = a + b 
(* 
val inline add : 
    a: ^a -> b: ^b -> ^c 
    when (^a or ^b) : (static member (+) : ^a * ^b -> ^c) 
*) 
add "Hello " "World!" 
// val it : string = "Hello World!" 
add 2 3 
// val it : int = 5 
संबंधित मुद्दे