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