হাস্কেল প্রিন্টফ কীভাবে কাজ করে?


104

হাস্কেলের ধরণের সুরক্ষা কেবল নির্ভরশীল-টাইপ করা ভাষার চেয়ে দ্বিতীয় নয় । তবে টেক্সট.প্রিন্টফের সাথে কিছু গভীর যাদু চলছে যা টাইপ- উইঙ্কি বলে মনে হচ্ছে।

> 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
আপনি নির্ভরশীল প্রকারগুলি ব্যবহার করে কেবল কোনও প্রকার নিরাপদ মুদ্রণযোগ্য পেতে পারেন।
augustss

9
লেনার্ট একদম ঠিক আছে। হাস্কেলের ধরণের সুরক্ষা হাস্কেলের চেয়ে আরও বেশি নির্ভরশীল ধরণের ভাষার সাথে দ্বিতীয়। অবশ্যই, আপনি যদি ফর্ম্যাটটির জন্য স্ট্রিংয়ের চেয়ে আরও তথ্যমূলক টাইপ চয়ন করেন তবে আপনি একটি প্রিন্টফ-জাতীয় জিনিস টাইপ নিরাপদ করতে পারেন।
শূকরকর্ম


1
@ অগাস্টস আপনি কেবল নির্ভরশীল প্রকারগুলি ব্যবহার করে টাইপ-সেফ প্রিন্টফ পেতে পারেন বা নমুনা হেস্কেল! ;-)
ম্যাথমেটিক্যালআরচিড

3
@ গণিতের অর্কিড টেম্পলেট হাস্কেল গণনা করে না। :)
augustss

উত্তর:


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আসে 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) 

দুর্দান্ত উত্তর। আমি কেবল এটিই নির্দেশ করতে চেয়েছিলাম যে প্রয়োগ করা যুক্তিগুলির ভিত্তিতে হ্যাস্কেল ফু এর ধরণের সন্ধান করছে। (-> Y -> আই () foo বিন্যাস :: (x দেখান, দেখান Y) => x) এর 3 "হ্যালো" λ>: এই বুঝতে, আপনি নিম্নরূপ ফু সুনির্দিষ্টভাবে প্রকার চাইতে পারেন
redfish64

1
আমি যখন বুঝতে পারি যে পরিবর্তনশীল দৈর্ঘ্যের আর্গুমেন্ট অংশটি কীভাবে প্রয়োগ করা হয়, তখনও আমি বুঝতে পারি না যে সংকলকটি কীভাবে প্রত্যাখ্যান করে printf "%d" True। এটি আমার কাছে খুব রহস্যময়, কারণ মনে হচ্ছে রানটাইম (?) মান "%d"একটি সংকলনের সময় সংকলনের সময় ডিক্রিফার হয়ে যায় Int। এটি আমার কাছে একেবারে বিস্মিত। । । বিশেষ করে সোর্স কোড ভালো জিনিস ব্যবহার করে না DataKindsবা TemplateHaskell(আমি সোর্স কোড চেক করা, কিন্তু এটা বোঝা করা হয়নি।)
থমাস Eding

2
@ থমাস এডিং কারণটি সংকলকটি প্রত্যাখ্যান করেছে printf "%d" Trueকারণ এর কোনও Boolউদাহরণ নেই PrintfArg। যদি আপনি কোনও ভুল টাইপের একটি যুক্তি পাস করেন যার উদাহরণ রয়েছে PrintfArg, এটি রানটাইমগুলিতে সংকলন করে এবং ব্যতিক্রম ছুঁড়ে দেয়। প্রাক্তন:printf "%d" "hi"
ট্র্যাভিস সুন্দরল্যান্ড
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.