2010-01-29 11 views
24

मैंने अभी मोनो में एफ # के साथ घूमना शुरू कर दिया और निम्नलिखित समस्या उत्पन्न हुई कि मैं काफी समझ नहीं पा रहा हूं। printfn और TextWriterFormat पर जानकारी को देखकर या तो ज्ञान नहीं आया, इसलिए मैंने सोचा कि मैं यहां पूछने जा रहा हूं।एफ # में printfn का प्रकार, स्थिर बनाम गतिशील स्ट्रिंग

> "hello";; 
val it : string = "hello" 
> printfn "hello";; 
hello 
val it : unit =() 

बस एक सामान्य स्ट्रिंग और यह मुद्रण:

FSI में मैं निम्नलिखित चलाते हैं। ठीक।

> let v = "hello" in printfn v ;; 
let v = "hello" in printfn v ;; 
---------------------------^ 
\...\stdin(22,28): error FS0001: The type 'string' is not compatible with the type 'Printf.TextWriterFormat<'a>' 

मैं अपने पढ़ने से समझ गया कि printfn एक निरंतर स्ट्रिंग की आवश्यकता है: अब मैं एक चर घोषणा करते हैं कि एक ही स्ट्रिंग को रोकने के लिए और यह रूप में अच्छी तरह मुद्रित करने के लिए करना चाहता था। मैं यह भी समझता हूं कि मैं इस समस्या को printfn "%s" v जैसे कुछ के साथ प्राप्त कर सकता हूं।

हालांकि, मैं समझना चाहता हूं कि यहां टाइपिंग के साथ क्या चल रहा है। स्पष्ट रूप से, "hello" प्रकार string के साथ-साथ v है। तब एक प्रकार की समस्या क्यों है? printfn कुछ खास है? जैसा कि मैं समझता हूं कि संकलक पहले स्ट्रिंग के तर्कों पर पहले से ही टाइप-चेकिंग करता है, जैसे कि printfn "%s" 1 विफल रहता है .. यह निश्चित रूप से गतिशील तारों के साथ काम नहीं कर सकता है, लेकिन मुझे लगता है कि संकलक-पक्ष से केवल एक सुविधा है स्थैतिक मामला

उत्तर

25

अच्छा सवाल। यदि आप printfn के प्रकार को देखते हैं, जो Printf.TextWriterFormat<'a> -> 'a है, तो आप देखेंगे कि संकलक स्वचालित रूप से संकलन समय पर TextWriterFormat ऑब्जेक्ट्स में तारों को जोड़ता है, उचित प्रकार पैरामीटर 'a का उपयोग करता है। आप एक गतिशील तार के साथ printfn का उपयोग करना चाहते हैं, तो आप सिर्फ इतना है कि रूपांतरण खुद के प्रदर्शन कर सकते हैं: स्ट्रिंग स्थिर (उपरोक्त उदाहरण में बताया) में जाना जाता है

let s = Printf.TextWriterFormat<unit>("hello") 
printfn s 

let s' = Printf.TextWriterFormat<int -> unit>("Here's an integer: %i") 
printfn s' 10 

let s'' = Printf.TextWriterFormat<float -> bool -> unit>("Float: %f; Bool: %b") 
printfn s'' 1.0 true 

है, तो आप अभी भी संकलक सही अनुमान कर हो सकता है बल्कि निर्माता बुला से TextWriterFormat के लिए सामान्य तर्क:

let (s:Printf.TextWriterFormat<_>) = "hello" 
let (s':Printf.TextWriterFormat<_>) = "Here's an integer: %i" 
let (s'':Printf.TextWriterFormat<_>) = "Float: %f; Bool: %b" 

तो स्ट्रिंग सही मायने में गतिशील है (उदाहरण के लिए यह एक फ़ाइल से पढ़ने रहा है), तो आप स्पष्ट रूप से प्रकार पैरामीटर का उपयोग करें और निर्माता फोन के रूप में मैंने किया था की आवश्यकता होगी पिछले उदाहरणों में।

7

मुझे नहीं लगता कि यह कहना सही है कि शाब्दिक मूल्य "हैलो" String प्रकार है जब printfn "hello" के संदर्भ में उपयोग किया जाता है। इस संदर्भ में संकलक Printf.TextWriterFormat<unit> के रूप में शाब्दिक मान के प्रकार का अनुमान लगाता है।

सबसे पहले यह मेरे लिए अजीब लग रहा था कि एक शाब्दिक स्ट्रिंग मान का उपयोग अलग-अलग प्रकार के संदर्भ में किया जाएगा, जहां इसका उपयोग किया गया था, लेकिन निश्चित रूप से हम इसका उपयोग करते हैं, संख्यात्मक अक्षर से निपटने के दौरान, जो पूर्णांक का प्रतिनिधित्व कर सकते हैं , decimals, floats, आदि, वे कहां दिखाई देते हैं के आधार पर।

आप printfn के माध्यम से इसे का उपयोग करने के लिये पहले चर घोषित करने के लिए चाहते हैं, आप इसे एक स्पष्ट प्रकार के साथ घोषणा कर सकते हैं ...

let v = "hello" : Printf.TextWriterFormat<unit> in printfn v 

... या आप निर्माता का उपयोग कर सकते Printf.TextWriterFormat कन्वर्ट करने के लिए एक सामान्य आवश्यक प्रकार के लिए स्ट्रिंग मान ...

let s = "foo" ;; 
let v = new Printf.TextWriterFormat<unit>(s) in printfn v ;; 
4

आप सही तरीके से पालन के रूप में, printfn समारोह एक "Printf.TextWriterFormat < 'एक>" एक स्ट्रिंग नहीं लेता है। कंपाइलर जानता है कि निरंतर स्ट्रिंग और "Printf.TextWriterFormat < 'a>" के बीच कैसे परिवर्तित करें, लेकिन गतिशील स्ट्रिंग और "Printf.TextWriterFormat <' a> के बीच नहीं।

यह सवाल पूछता है कि यह एक गतिशील स्ट्रिंग और "Printf.TextWriterFormat < 'ए> के बीच क्यों परिवर्तित नहीं हो सकता है। ऐसा इसलिए है क्योंकि संकलक को स्ट्रिंग की सामग्री को देखना चाहिए और यह निर्धारित करना चाहिए कि इसमें कौन से नियंत्रण वर्ण हैं (यानी% s% i आदि), इससे यह "printf.TextWriterFormat <" के प्रकार पैरामीटर के प्रकार को काम करता है। ए> "(यानी 'थोड़ा सा)। यह एक ऐसा फ़ंक्शन है जो printfn फ़ंक्शन द्वारा वापस किया जाता है और इसका मतलब है कि printfn द्वारा स्वीकार किए गए अन्य पैरामीटर अब दृढ़ता से टाइप किए गए हैं।

इसे अपने उदाहरण में थोड़ा स्पष्ट करने के लिए "printfn"% s "" "% s" को "printf.TextWriterFormat इकाई>" में परिवर्तित किया गया है, जिसका अर्थ है "printfn"% s "" स्ट्रिंग है -> इकाई।

7

यह केवल आपके प्रश्न से संबंधित कुछ है, लेकिन मुझे लगता है कि यह एक आसान चाल है। सी # में, मैं अक्सर, स्थिरांक के रूप में जमा String.Format साथ प्रयोग के लिए टेम्पलेट तार है के रूप में यह क्लीनर कोड के लिए बनाता है:

String.Format(SomeConstant, arg1, arg2, arg3) 

के बजाय ...

String.Format("Some {0} really long {1} and distracting template that uglifies my code {2}...", arg1, arg2, arg3) 

लेकिन चूंकि तरीकों में से printf परिवार का कहना है मूल्यों के बजाय शाब्दिक तारों पर, मैंने शुरू में सोचा था कि अगर मैं printf का उपयोग करना चाहता हूं तो मैं इस दृष्टिकोण का उपयोग F # में नहीं कर सका। लेकिन फिर मुझे एहसास हुआ कि एफ # में कुछ बेहतर है - आंशिक फ़ंक्शन एप्लिकेशन।

let formatFunction = sprintf "Some %s really long %i template %i" 

उसने अभी एक ऐसा फ़ंक्शन बनाया है जो इनपुट के रूप में एक स्ट्रिंग और दो पूर्णांक लेता है, और एक स्ट्रिंग देता है। यही कहना है, string -> int -> int -> string। यह निरंतर स्ट्रिंग से भी बेहतर है। फ़ार्मेट टेम्पलेट, क्योंकि यह एक दृढ़ता से टाइप की गई विधि है जो मुझे इनलाइन को शामिल किए बिना टेम्पलेट का फिर से उपयोग करने देती है।

let foo = formatFunction "test" 3 5 

जितना अधिक मैं एफ # का उपयोग करता हूं, उतना अधिक उपयोग मैं आंशिक फ़ंक्शन एप्लिकेशन के लिए खोजता हूं। उत्तम सामग्री।

संबंधित मुद्दे