हास्केल प्रिंटफ कैसे काम करता है?


104

हास्केल के प्रकार की सुरक्षा केवल निर्भरता-टाइप की गई भाषाओं के लिए दूसरी है । लेकिन Text.Printf के साथ कुछ गहरा जादू चल रहा है जो कि टाइप- विस्की लगता है।

> printf "%d\n" 3
3
> printf "%s %f %d" "foo" 3.3 3
foo 3.3 3

इसके पीछे क्या गहरा जादू है? कैसे कर सकते हैंText.Printf.printfफ़ंक्शन इस तरह के परिवर्तनशील तर्क ले ?

हास्केल में चर तर्कों के लिए अनुमति देने के लिए किस सामान्य तकनीक का उपयोग किया जाता है, और यह कैसे काम करता है?

(साइड नोट: इस तकनीक का उपयोग करते समय कुछ प्रकार की सुरक्षा स्पष्ट रूप से खो जाती है।)

> :t printf "%d\n" "foo"
printf "%d\n" "foo" :: (PrintfType ([Char] -> t)) => t

15
आप केवल निर्भर प्रकारों का उपयोग करके एक प्रकार का सुरक्षित प्रिंटफ़ प्राप्त कर सकते हैं।
अगस्त 19'11

9
लेन्नर्ट का काफी अधिकार है। हास्केल की तुलना में भी अधिक निर्भर प्रकारों वाली भाषाओं में हास्केल की प्रकार की सुरक्षा दूसरी है। यदि आप प्रारूप के लिए स्ट्रिंग की तुलना में अधिक जानकारीपूर्ण प्रकार चुनते हैं, तो निश्चित रूप से, आप एक प्रिंटफ जैसी चीज़ को सुरक्षित बना सकते हैं।
सुअर का बच्चा


1
@augustss आप केवल आश्रित प्रकारों का उपयोग कर एक प्रकार का सुरक्षित प्रिंट प्राप्त कर सकते हैं या अस्थायी का उपयोग कर सकते हैं! ;-)
मैथमैटिकलऑर्चिड

3
@MathematicalOrchid टेम्पलेट Haskell की गिनती नहीं है। :)
22

जवाबों:


131

ट्रिक का उपयोग टाइप क्लास के लिए होता है। के मामले में printf, कुंजी PrintfTypeप्रकार वर्ग है। यह किसी भी तरीके को उजागर नहीं करता है, लेकिन महत्वपूर्ण हिस्सा वैसे भी प्रकार में है।

class PrintfType r
printf :: PrintfType r => String -> r

तो printfएक अतिभारित वापसी प्रकार है। तुच्छ मामले में, हमारे पास कोई अतिरिक्त तर्क नहीं है, इसलिए हमें तत्काल rकरने में सक्षम होने की आवश्यकता है IO ()। इसके लिए, हमारे पास उदाहरण है

instance PrintfType (IO ())

अगला, तर्कों की एक चर संख्या का समर्थन करने के लिए, हमें उदाहरण के स्तर पर पुनरावृत्ति का उपयोग करने की आवश्यकता है। विशेष रूप से हमें एक उदाहरण की आवश्यकता है ताकि यदि rकोई हो PrintfType, तो फ़ंक्शन प्रकार x -> rभी एक है PrintfType

-- instance PrintfType r => PrintfType (x -> r)

बेशक, हम केवल तर्कों का समर्थन करना चाहते हैं जो वास्तव में स्वरूपित हो सकते हैं। यहीं दूसरा प्रकार वर्ग PrintfArgआता है। इसलिए वास्तविक उदाहरण है

instance (PrintfArg x, PrintfType r) => PrintfType (x -> r)

यहाँ एक सरलीकृत संस्करण है जो Showकक्षा में किसी भी तर्क को लेता है और उन्हें प्रिंट करता है:

{-# LANGUAGE FlexibleInstances #-}

foo :: FooType a => a
foo = bar (return ())

class FooType a where
    bar :: IO () -> a

instance FooType (IO ()) where
    bar = id

instance (Show x, FooType r) => FooType (x -> r) where
    bar s x = bar (s >> print x)

यहाँ, barएक IO कार्रवाई की जाती है जो पुनरावर्ती रूप से तब तक बनाई जाती है जब तक कि अधिक तर्क न हों, जिस बिंदु पर हम बस इसे निष्पादित करते हैं।

*Main> foo 3 :: IO ()
3
*Main> foo 3 "hello" :: IO ()
3
"hello"
*Main> foo 3 "hello" True :: IO ()
3
"hello"
True

क्विकचेक उसी तकनीक का भी उपयोग करता है, जहां Testableवर्ग में बेस केस के लिए एक उदाहरण होता है Bool, और फ़ंक्शंस के लिए एक पुनरावर्ती होता है जो Arbitraryकक्षा में तर्क लेता है ।

class Testable a
instance Testable Bool
instance (Arbitrary x, Testable r) => Testable (x -> r) 

बहुत बढ़िया जवाब। मैं सिर्फ यह बताना चाहता था कि हेकेल लगाए गए तर्कों के आधार पर फू के प्रकार का पता लगा रहा है। इसे समझने के लिए, आप फू एक्सप्लसिटी के प्रकार को इस प्रकार निर्दिष्ट करना चाह सकते हैं: λ> (foo :: (शो x, शो y) => x -> y -> IO ()) 3 "हैलो"
redfish64

1
जबकि मैं समझता हूं कि चर लंबाई तर्क भाग कैसे लागू किया जाता है, मैं अभी भी नहीं समझता कि संकलक कैसे अस्वीकार करता है printf "%d" True। यह मेरे लिए बहुत रहस्यमय है, क्योंकि ऐसा लगता है कि रनटाइम (?) मूल्य "%d"को एक आवश्यकता के लिए संकलन समय पर डिक्रिप्ट हो जाता है Int। यह मेरे लिए बिल्कुल चौंकाने वाला है। । । विशेष रूप से चूंकि सोर्स कोड चीजों का उपयोग नहीं करता है DataKindsया TemplateHaskell(मैंने स्रोत कोड की जांच की है, लेकिन इसे समझ नहीं पाया।)
थॉमस एडिंग

2
@ThomasEding संकलक अस्वीकार करने का कारण यह printf "%d" Trueहै कि कोई Boolउदाहरण नहीं है PrintfArg। आपको लगता है कि गलत प्रकार का एक तर्क पार कर लेते हैं करता है का एक उदाहरण है PrintfArg, यह संकलन करता है और रनटाइम पर एक अपवाद फेंकता है। Ex:printf "%d" "hi"
ट्रैविस सुंदरलैंड
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.