2015-09-29 10 views
6

पैदा करता है जब मैं कोड निष्पादितलाइन रहस्यमय त्रुटि

let (a,p) = (2+2, Printf.printf) in p "abc"; p "%d" 3 ;; 

मैं उत्पादन abc3 देखते हैं, लेकिन बजाय

File "f.ml", line 1, characters 46-47: 
Error: This function has type (unit, out_channel, unit) format -> unit 
     It is applied to too many arguments; maybe you forgot a `;'. 

मज़ा करना होता है कि अगर मैं बदल 2+22 को प्राप्त करने की उम्मीद , यह चलता है।

कोड एक त्रुटि उत्पन्न क्यों करता है, लेकिन +2 के साथ नहीं हटाया गया है?

+0

मैं भी जवाब में दिलचस्पी है, इस प्रथम दृष्टया अजीब है। –

उत्तर

6

printf और मूल्य polymorphism के लिए ओकैमल की विशेष टाइपिंग चाल का एक संयोजन।

जैसा कि आप शायद जानते हैं, Printf.printfstring नहीं लेता है लेकिन डेटा प्रकार format है। OCaml प्रकार चेकर printf के लिए स्ट्रिंग शाब्दिक की टाइपिंग के लिए एक विशेष नियम है: अगर संदर्भ का अनुरोध करता है अगर यह format के रूप में लिखा गया:

# "%d";; 
- : string = "%d" 
# ("%d" : _format);; 
- : (int -> 'a, 'b, 'a) format = ... 

OCaml प्रकार प्रणाली एक और चाल बुलाया मूल्य बहुरूपता है (अधिक सटीक है, यह आराम से मूल्य है बहुरूपता)। इसका उद्देश्य साइड इफेक्ट्स के साथ अभिव्यक्ति टाइप करना है। मैं इसके विवरण की व्याख्या नहीं करते, लेकिन यह बहुरूपता अनुमति नहीं देता: भाव के कुछ रूपों बुलाया "विशाल" बहुरूपी प्रकार नहीं हो सकता:

# fun x -> x;; 
- : 'a -> 'a = <fun> 
# (fun x -> x) (fun x -> x) 
- : '_a -> '_a = <fun> 

ऊपर में, (fun x -> x) (fun x -> x) कोई बहुरूपी प्रकार है, पहचान समारोह fun x -> x है, जबकि। यह (fun x -> x) (fun x -> x) की अभिव्यक्ति के आकार के कारण है: यह "विशाल" है। अजीब प्रकार परिवर्तनीय '_a मोनोमोर्फिक प्रकार परिवर्तनीय है: इसे केवल एक बार किसी प्रकार के लिए तत्काल किया जा सकता है। दूसरी ओर, 'a जैसे पॉलीमोर्फिक चर जैसे vlaue के प्रत्येक उपयोग के लिए एक अलग प्रकार के लिए तत्काल किया जा सकता है।

के अपने कोड पर वापस चलते हैं:

# let (a, p) = (2, Printf.printf);; 
val a : int 
val p : ('a, out_channel, unit) format -> 'a 

यहाँ, p एक बहुरूपी प्रकार ('a, out_channel, unit) format -> 'a है। 'a को एक से अधिक प्रकारों में तत्काल किया जा सकता है इसलिए p "abc"; p "%d" 3 टाइप करने योग्य है: p के पहले उपयोग के लिए और (int -> unit, out_channel, unit) format -> int -> unitp के दूसरे उपयोग के लिए पॉलीमोर्फिक प्रकार को (unit, out_channel, unit) format -> unit पर तुरंत चालू किया जा सकता है।

एक बार जब आप बदल निरंतर 22+2 है, जो विशाल है, पूरे अभिव्यक्ति भी प्रशस्त हो जाता है, और टाइपिंग परिवर्तन:

# let (a, p) = (2+2, Printf.printf);; 
val a : int 
val p : ('_a, out_channel, unit) format -> '_a 

यहाँ, p अब बहुरूपी चर 'a लेकिन monomorphic '_a है। p के पहले उपयोग पर यह मोनोमोर्फिक वैरिएबल unit को एकीकृत (तत्काल) एकीकृत किया गया है, और परिणामस्वरूप p का प्रकार (unit, out_channel, unit) format -> unit बन गया है। इसमें केवल 1 तर्क हो सकता है इसलिए 2 तर्कों के साथ p के दूसरे उपयोग की टाइपिंग विफल हो जाती है।

एक आसान तरीका इस स्थिति से बचने के लिए दो भागों में अपनी परिभाषा को विभाजित करने के लिए है:

let a = 2 + 2 in 
let p = Printf.printf in 
p "abc"; p "%d" 3 
संबंधित मुद्दे