क्या उच्च-स्तरीय पैरामीट्रिक बहुरूपता उपयोगी है?


16

मुझे पूरा यकीन है कि हर कोई फॉर्म के सामान्य तरीकों से परिचित है:

T DoSomething<T>(T item)

इस फ़ंक्शन को पैरामीट्रिक पॉलीमॉर्फ़िक (पीपी) भी कहा जाता है, विशेष रूप से रैंक -1 पीपी।

मान लें कि इस विधि को फॉर्म के फ़ंक्शन ऑब्जेक्ट का उपयोग करके दर्शाया जा सकता है:

<T> : T -> T

यही है, <T>इसका मतलब है कि यह एक प्रकार का पैरामीटर लेता है, और T -> Tइसका मतलब है कि यह एक प्रकार का पैरामीटर लेता है Tऔर उसी प्रकार का मान लौटाता है।

फिर एक रैंक -2 पीपी समारोह होगा:

(<T> : T -> T) -> int 

फ़ंक्शन कोई प्रकार का पैरामीटर नहीं लेता है, लेकिन एक फ़ंक्शन लेता है जो एक प्रकार का पैरामीटर लेता है। आप इसे पुनरावृत्त रूप से जारी रख सकते हैं, घोंसले को अधिक से अधिक गहरा बना सकते हैं, उच्च और उच्च रैंक का पीपी प्राप्त कर सकते हैं।

प्रोग्रामिंग भाषाओं के बीच यह सुविधा वास्तव में दुर्लभ है। यहां तक ​​कि हास्केल इसे डिफ़ॉल्ट रूप से अनुमति नहीं देता है।

क्या यह उपयोगी है? क्या यह उन व्यवहारों का वर्णन कर सकता है जो अन्यथा वर्णन करना मुश्किल है?

इसके अलावा, किसी चीज़ के प्रतिरूप होने का क्या मतलब है ? (इस सन्दर्भ में)


1
दिलचस्प है, टाइपस्क्रिप्ट पूर्ण रैंक-एन पीपी समर्थन के साथ एक मुख्यधारा की भाषा है। उदाहरण के लिए, निम्न प्रकार मान्य है टाइपस्क्रिप्ट कोड:let sdff = (g : (f : <T> (e : T) => void) => void) => {}
ग्रेगोस

जवाबों:


11

सामान्य तौर पर, आप उच्च-श्रेणी के बहुरूपता का उपयोग करते हैं जब आप चाहते हैं कि कॉलली एक प्रकार के पैरामीटर के मूल्य का चयन करने में सक्षम हो, बजाय कॉलर के । उदाहरण के लिए:

f :: (forall a. Show a => a -> Int) -> (Int, Int)
f g = (g "one", g 2)

कोई भी फ़ंक्शन gजो मैं इसे पास करता हूं, fमुझे Intकिसी प्रकार के मूल्य से मुझे देने में सक्षम होना चाहिए , जहां केवल एक चीज gउस प्रकार के बारे में जानती है कि इसका एक उदाहरण है Show। तो ये कोषेर हैं:

f (length . show)
f (const 42)

लेकिन ये नहीं हैं:

f length
f succ

एक विशेष रूप से उपयोगी अनुप्रयोग मानों की स्कूपिंग को लागू करने के लिए प्रकारों के स्कोपिंग का उपयोग करने में है । मान लीजिए कि हमारे पास एक प्रकार की वस्तु है Action<T>, एक कार्रवाई का प्रतिनिधित्व करते हुए हम Tभविष्य या कॉलबैक जैसे प्रकार के परिणाम का उत्पादन कर सकते हैं ।

T runAction<T>(Action<T>)

runAction :: forall a. Action a -> a

अब, मान लीजिए कि हमारे पास एक Actionऐसा भी है जो Resource<T>वस्तुओं को आवंटित कर सकता है:

Action<Resource<T>> newResource<T>(T)

newResource :: forall a. a -> Action (Resource a)

हम यह लागू करना चाहते हैं कि उन संसाधनों का उपयोग केवल उसी Actionजगह के अंदर किया जाता है जहां वे बनाए गए थे, और विभिन्न कार्यों या एक ही कार्रवाई के अलग-अलग रन के बीच साझा नहीं किए गए थे, ताकि क्रियाएं नियतात्मक और दोहराव योग्य हों।

हम इसे और प्रकारों के Sलिए एक पैरामीटर जोड़कर पूरा करने के लिए उच्च-रैंक वाले प्रकारों का उपयोग कर सकते हैं , जो कि पूरी तरह से सार है- यह "गुंजाइश" का प्रतिनिधित्व करता है । अब हमारे हस्ताक्षर हैं:ResourceActionAction

T run<T>(<S> Action<S, T>)
Action<S, Resource<S, T>> newResource<T>(T)

runAction :: forall a. (forall s. Action s a) -> a
newResource :: forall s a. a -> Action s (Resource s a)

अब जब हम runActionएक Action<S, T>देते हैं, तो हमें विश्वास दिलाया जाता है कि क्योंकि "स्कोप" पैरामीटर Sपूरी तरह से बहुरूपी है, यह runActionकिसी भी प्रकार के किसी भी मूल्य के शरीर से बच नहीं सकता है, Sजैसे कि उपयोग करता है जैसे कि Resource<S, int>बच नहीं सकता है!

(हास्केल में, यह STमठ के रूप में जाना जाता है , जहां runActionकहा जाता है runST, Resourceकहा जाता है STRef, और newResourceकहा जाता है newSTRef।)


STइकाई एक बहुत ही दिलचस्प उदाहरण है। क्या आप कुछ और उदाहरण दे सकते हैं कि उच्च-श्रेणी का बहुरूपता कब उपयोगी होगा?
ग्रेगोरोस

@ ग्रेग्रोस: यह अस्तित्व के साथ भी काम करता है। में Haxl , हम एक अस्तित्व की तरह था data Fetch d = forall a. Fetch (d a) (MVar a), जो एक डेटा स्रोत के लिए एक अनुरोध की एक जोड़ी है dऔर जिसमें परिणाम स्टोर करने के लिए एक स्लॉट। परिणाम और स्लॉट में मिलान प्रकार होना चाहिए, लेकिन वह प्रकार छिपा हुआ है, इसलिए आपके पास समान डेटा स्रोत के अनुरोधों की एक विषम सूची हो सकती है। अब आप उच्च-रैंक बहुरूपता का उपयोग एक फ़ंक्शन लिखने के लिए कर सकते हैं जो सभी अनुरोधों को प्राप्त करता है, एक फ़ंक्शन जो एक को प्राप्त करता है fetch :: (forall a. d a -> IO a) -> [Fetch d] -> IO ():।
जॉन पूर्डी

8

उच्च रैंक बहुरूपता अत्यंत उपयोगी है। सिस्टम एफ में (टाइप एफपी भाषाओं की मूल भाषा जिससे आप परिचित हैं), यह "टाइप चर्च एन्कोडिंग" को स्वीकार करने के लिए आवश्यक है जो वास्तव में सिस्टम एफ प्रोग्रामिंग कैसे करता है। इनके बिना, सिस्टम एफ पूरी तरह से बेकार है।

सिस्टम एफ में, हम संख्याओं को परिभाषित करते हैं

Nat = forall c. (c -> c) -> c -> c

जोड़ के पास प्रकार है

plus : Nat -> Nat -> Nat
plus l r = Λ t. λ (s : t -> t). λ (z : t). l s (r s z)

जो एक उच्च रैंक प्रकार है ( forall c.उन तीरों के अंदर दिखाई देता है)।

यह अन्य जगहों पर भी आता है। उदाहरण के लिए, यदि आप इंगित करना चाहते हैं कि एक संगणना एक उचित निरंतरता शैली है (Google "कोडेन्सिटी हैसेल") तो आप इसे इस रूप में सही करेंगे

type CPSed A = forall c. (A -> c) -> c

यहां तक ​​कि सिस्टम एफ में निर्जन प्रकार के बारे में बात करने के लिए उच्च रैंक बहुरूपता की आवश्यकता होती है

type Void = forall a. a 

अगर यह एक दिलचस्प प्रकार के डेटा से निपटना चाहता है, तो लंबे और छोटे, शुद्ध प्रकार की प्रणाली (सिस्टम एफ, सीओसी) में एक फ़ंक्शन लिखने के लिए उच्च रैंक बहुरूपता की आवश्यकता होती है।

विशेष रूप से सिस्टम एफ में, इन एन्कोडिंग को "impredicative" होने की आवश्यकता है। इसका मतलब यह है कि सभी प्रकारोंforall a. पर एक मात्रा निर्धारित करता है । यह गंभीर रूप से उसी प्रकार को शामिल करता है जिसे हम परिभाषित कर रहे हैं। में है कि वास्तव में के लिए खड़े हो सकता है फिर से! एमएल जैसी भाषाओं में ऐसा नहीं होता है, क्योंकि उन्हें कहा जाता है कि वे "प्रेडिक्टिव" हैं क्योंकि एक प्रकार का वैरिएबल केवल क्वांटिफायर के बिना सेट के प्रकार पर निर्भर करता है (जिसे मोनोटाइप कहा जाता है)। आवश्यक impredicativity की हमारी परिभाषा के रूप में अच्छी तरह से क्योंकि हम में होने के लिए Instantiated !forall a. aaforall a. apluscl : NatNat

अंत में, मैं एक अंतिम कारण का उल्लेख करना चाहूंगा, जहां आप एक भाषा में भी उच्च श्रेणी के बहुरूपता और उच्च श्रेणी के बहुरूपता को मनमाने ढंग से पुनरावर्ती प्रकार (सिस्टम एफ के विपरीत) के साथ पसंद करेंगे। हास्केल में, "राज्य थ्रेड मोनाड" नामक प्रभावों के लिए एक भिक्षु है। विचार यह है कि स्टेट थ्रेड मोनाड आपको चीजों को म्यूट करने देता है, लेकिन इसे बचने की आवश्यकता है कि आपका परिणाम किसी भी चीज पर निर्भर नहीं है। इसका मतलब यह है कि एसटी अभिकलन पर्यवेक्षित रूप से शुद्ध हैं। इस आवश्यकता को लागू करने के लिए हम उच्च रैंक बहुरूपता का उपयोग करते हैं

runST :: forall a. (forall s. ST s a) -> a

यहां यह सुनिश्चित करके कि aहम जिस दायरे में हैं, उसके दायरे से बाहर हैं s, हम जानते हैं कि यह aएक अच्छी तरह से बना हुआ है जिस पर भरोसा नहीं किया जाता है s। हम sउस विशेष राज्य के धागे में सभी उत्परिवर्तनीय चीजों को समाहित करने के लिए उपयोग करते हैं ताकि हमें पता चल जाए कि aवह उत्परिवर्तित चीजों से स्वतंत्र है और इस प्रकार कुछ भी उस STसंगणना के दायरे से बचता है ! प्रकारों का उपयोग करने का एक अद्भुत उदाहरण बीमार कार्यक्रमों का शासन करने के लिए।

वैसे, अगर आप टाइप थ्योरी के बारे में जानने में रुचि रखते हैं तो मैं एक अच्छी किताब या दो में निवेश करने का सुझाव दूंगा। यह सामान बिट्स और टुकड़ों में सीखना मुश्किल है। मैं सामान्य रूप से पीएल सिद्धांत पर पियर्स या हार्पर की पुस्तकों में से एक का सुझाव देता हूं (और कुछ प्रकार के सिद्धांत)। पुस्तक "प्रकार और प्रोग्रामिंग भाषाओं में उन्नत विषय" भी प्रकार के सिद्धांत की एक अच्छी मात्रा को कवर करती है। अंत में "मार्टिन लोफ के प्रकार के सिद्धांत में प्रोग्रामिंग" एक बहुत अच्छा प्रदर्शनी है जो कि आयामी प्रकार के सिद्धांत मार्टिन लोफ में उल्लिखित है।


आपकी सिफारिशों के लिए धन्यवाद। मैं उन्हें देखूंगा। विषय वास्तव में दिलचस्प है, और मैं चाहता हूं कि कुछ और उन्नत प्रकार की प्रणाली अवधारणाओं को और अधिक प्रोग्रामिंग भाषाओं द्वारा अपनाया जाएगा। वे आपको बहुत अधिक अभिव्यंजक शक्ति प्रदान करते हैं।
ग्रेग्रोस
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.