ट्रिक का उपयोग टाइप क्लास के लिए होता है। के मामले में 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)