GADT এর অন্তর্ভুক্ত forall সরবরাহ করে অস্তিত্বমূলক প্রকারগুলি ব্যবহার করে কোডের স্পষ্ট এবং আরও ভাল সিনট্যাক্স সরবরাহ করে
আমি মনে করি যে GADT বাক্য গঠন আরও ভাল যে সাধারণ চুক্তি আছে। আমি এটি বলব না যে এটি জিএডিডিগুলি অন্তর্নিহিত ফোরায়েল সরবরাহ করে, বরং এটি ExistentialQuantification
এক্সটেনশান সহ সক্ষম হওয়া মূল সিনট্যাক্সটি সম্ভবত বিভ্রান্ত / বিভ্রান্তিকর। এই বাক্য গঠনটি অবশ্যই দেখায়:
data SomeType = forall a. SomeType a
বা একটি বাধা সহ:
data SomeShowableType = forall a. Show a => SomeShowableType a
এবং আমি মনে করি যে sensক্যমত্যটি হ'ল forall
এখানে কীওয়ার্ড ব্যবহারের ফলে প্রকারটি সম্পূর্ণ ভিন্ন ধরণের সাথে সহজেই বিভ্রান্ত হতে পারে:
data AnyType = AnyType (forall a. a) -- need RankNTypes extension
আরও ভাল সিনট্যাক্স একটি পৃথক exists
কীওয়ার্ড ব্যবহার করতে পারে , তাই আপনি লিখতে চাই:
data SomeType = SomeType (exists a. a) -- not valid GHC syntax
অন্তর্নিহিত বা স্পষ্টরূপে ব্যবহৃত GADT বাক্য গঠনটি এই ধরণেরগুলির forall
মধ্যে আরও অভিন্ন এবং এটি বোঝা আরও সহজ বলে মনে হয়। এমনকি একটি স্পষ্টতা সহ forall
, নিম্নলিখিত সংজ্ঞাটি এই ধারণাটি জুড়ে যায় যে আপনি যে কোনও ধরণের মান নিতে পারেন a
এবং এটি মনোমরফিকের ভিতরে রাখতে পারেন SomeType'
:
data SomeType' where
SomeType' :: forall a. (a -> SomeType') -- parentheses optional
এবং এই ধরণের এবং এর মধ্যে পার্থক্যটি দেখতে এবং বোঝা সহজ:
data AnyType' where
AnyType' :: (forall a. a) -> AnyType'
অস্তিত্বের প্রকারগুলি তাদের যে ধরণের ধারণাগুলি রয়েছে তাতে আগ্রহী বলে মনে হয় না তবে তাদের সাথে মেলে প্যাটার্নটি বলে যে এমন কিছু প্রকার রয়েছে যা আমরা টাইপ বা ডেটা ব্যবহার না করা অবধি এটি কী প্রকারের তা জানি না।
আমরা প্রকারগুলি গোপন করতে চাইলে সেগুলি ব্যবহার করি (উদাহরণস্বরূপ: ভিন্ন ভিন্ন তালিকাগুলির জন্য) বা কমপাইল টাইমের প্রকারগুলি কী তা আমরা সত্যই জানি না।
আমার ধারণা, এগুলি খুব বেশি দূরে নয়, যদিও আপনাকে অস্তিত্বের ধরণের ব্যবহার Typeable
বা ব্যবহার করতে হবে না Data
। আমি মনে করি এটি বলাই আরও সঠিক হবে যে অস্তিত্বহীন টাইপ একটি অনির্দিষ্ট টাইপের চারপাশে একটি ভাল টাইপযুক্ত "বাক্স" সরবরাহ করে। বাক্সটি এক অর্থে প্রকারটি "আড়াল" করে, যা আপনাকে এই ধরণের বাক্সগুলির একটি ভিন্নধর্মী তালিকা তৈরি করতে দেয়, এতে থাকা ধরণের উপেক্ষা করে। দেখা যাচ্ছে যে SomeType'
উপরের মতো একটি নিয়ন্ত্রণহীন অস্তিত্বগুলি বেশ অকেজো, তবে একটি সীমাবদ্ধ প্রকার:
data SomeShowableType' where
SomeShowableType' :: forall a. (Show a) => a -> SomeShowableType'
আপনাকে "বাক্স" এর ভিতরে উঁকি দিতে এবং ধরণের শ্রেণিবদ্ধ সুবিধাগুলি উপলভ্য করার জন্য প্যাটার্ন ম্যাচের অনুমতি দেয়:
showIt :: SomeShowableType' -> String
showIt (SomeShowableType' x) = show x
মনে রাখবেন যে এটি কেবল Typeable
বা না কোনও ধরণের শ্রেণির জন্য কাজ করে Data
।
স্লাইড ডেকের 20 পৃষ্ঠাগুলি সম্পর্কে আপনার বিভ্রান্তির বিষয়ে, লেখক বলছেন যে কোনও ফাংশনের পক্ষে এটি একটি অসম্ভব যা একটি নির্দিষ্ট উদাহরণের Worker
দাবিতে অস্তিত্ব গ্রহণWorker
করে Buffer
। আপনি Worker
একটি নির্দিষ্ট ধরণের ব্যবহার করে তৈরি করতে একটি ফাংশন লিখতে পারেন Buffer
, যেমন MemoryBuffer
:
class Buffer b where
output :: String -> b -> IO ()
data Worker x = forall b. Buffer b => Worker {buffer :: b, input :: x}
data MemoryBuffer = MemoryBuffer
instance Buffer MemoryBuffer
memoryWorker = Worker MemoryBuffer (1 :: Int)
memoryWorker :: Worker Int
তবে আপনি যদি এমন কোনও ফাংশন লিখেন যা একটি Worker
যুক্তি হিসাবে গ্রহণ করে , তবে এটি কেবলমাত্র সাধারণ Buffer
ধরণের শ্রেণীর সুবিধা (যেমন, ফাংশন output
) ব্যবহার করতে পারে:
doWork :: Worker Int -> IO ()
doWork (Worker b x) = output (show x) b
b
প্যাটার্ন ম্যাচিংয়ের মাধ্যমে এমনকি এটি একটি বিশেষ ধরণের বাফার হওয়ার দাবি করার চেষ্টা করতে পারে না :
doWorkBroken :: Worker Int -> IO ()
doWorkBroken (Worker b x) = case b of
MemoryBuffer -> error "try this" -- type error
_ -> error "try that"
পরিশেষে, অস্তিত্বমূলক প্রকার সম্পর্কিত রানটাইম তথ্য জড়িত টাইপক্লাসগুলির জন্য অন্তর্নিহিত "অভিধান" আর্গুমেন্টের মাধ্যমে উপলব্ধ করা হয়। Worker
টাইপ উপরে বাফার এবং ইনপুট জন্য ক্ষেত্র হচ্ছে addtion মধ্যে, এছাড়াও একটি অদৃশ্য অন্তর্নিহিত ক্ষেত্র পয়েন্ট যে হয়েছে Buffer
অভিধান (কিছুটা ভি-টেবিল মত, যদিও এটা কমই বিশাল, এটা ঠিক উপযুক্ত একটি পয়েন্টার রয়েছে যেমন output
ফাংশন)।
অভ্যন্তরীণভাবে, টাইপ শ্রেণিটি Buffer
ফাংশন ক্ষেত্রগুলির সাথে ডেটা টাইপ হিসাবে উপস্থাপিত হয় এবং উদাহরণগুলি এই ধরণের "অভিধান" থাকে:
data Buffer' b = Buffer' { output' :: String -> b -> IO () }
dBuffer_MemoryBuffer :: Buffer' MemoryBuffer
dBuffer_MemoryBuffer = Buffer' { output' = undefined }
অস্তিত্বের ধরণের এই অভিধানের জন্য একটি গোপন ক্ষেত্র রয়েছে:
data Worker' x = forall b. Worker' { dBuffer :: Buffer' b, buffer' :: b, input' :: x }
এবং doWork
অস্তিত্বের Worker'
মানগুলিতে পরিচালনা করে এমন একটি ফাংশন হিসাবে প্রয়োগ করা হয়:
doWork' :: Worker' Int -> IO ()
doWork' (Worker' dBuf b x) = output' dBuf (show x) b
শুধুমাত্র একটি ফাংশন সহ একটি ধরণের শ্রেণীর জন্য অভিধানটি আসলে নতুন টাইপকে অনুকূলিত করে তোলে, সুতরাং উদাহরণস্বরূপ, অস্তিত্বের ধরণটিতে Worker
একটি গোপন ক্ষেত্র অন্তর্ভুক্ত থাকে output
যা বাফারের জন্য ফাংশনটির জন্য একটি ফাংশন পয়েন্টার ধারণ করে এবং এটি কেবলমাত্র রানটাইম তথ্য প্রয়োজন দ্বারা doWork
।