কৌশলটি হ'ল টাইপ ক্লাস ব্যবহার করা। এর ক্ষেত্রে 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
আসে So সুতরাং আসল উদাহরণটি
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
একটি আইও পদক্ষেপ গ্রহণ করে যা পুনরুক্তি দিয়ে তৈরি করা হয় যতক্ষণ না আর কোনও যুক্তি না উপস্থিত থাকে, যার পর্যায়ে আমরা কেবল এটি সম্পাদন করি।
*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)