7

मैं प्रकार के परिवारों के साथ अभिव्यक्तियों का प्रतिनिधित्व करने की कोशिश कर रहा हूं, लेकिन मुझे लगता है कि मैं जो बाधाओं को लिखना चाहता हूं, उसे समझने की प्रतीत नहीं कर रहा हूं, और मुझे ऐसा लगता है कि यह संभव नहीं है। यहां मेरा कोड है:प्रकार बाधाओं के साथ हास्केल प्रकार पारिवारिक उदाहरण

class Evaluable c where 
    type Return c :: * 
    evaluate :: c -> Return c 

data Negate n = Negate n 

instance (Evaluable n, Return n ~ Int) => Evaluable (Negate n) where 
    type Return (Negate n) = Return n 
    evaluate (Negate n) = negate (evaluate n) 

यह सब ठीक से संकलित करता है, लेकिन यह बिल्कुल ठीक नहीं है जो मैं चाहता हूं। NegateEvaluable के उदाहरण की बाधाओं में, मैं कहता हूं कि Negate के अंदर अभिव्यक्ति का वापसी प्रकार Int (Return n ~ Int के साथ) होना चाहिए ताकि मैं उस पर नकारात्मकता कह सकूं, लेकिन यह बहुत ही सीमित है। रिटर्न प्रकार वास्तव में केवल Num प्रकार वर्ग का उदाहरण होना चाहिए जिसमें negate फ़ंक्शन है। इस तरह Double एस, Integer एस, या Num के किसी भी अन्य उदाहरण को भी अस्वीकार कर दिया जा सकता है और न केवल Int एस। लेकिन मैं सिर्फ

Return n ~ Num 

नहीं लिख सकते हैं बजाय क्योंकि Num एक प्रकार वर्ग है और Return n एक प्रकार है। मैं

Num (Return n) 

इसके बजाय Return n एक प्रकार का प्रकार नहीं है।

क्या मैं हास्केल के साथ भी संभव करने की कोशिश कर रहा हूं? यदि नहीं, तो क्या यह होना चाहिए, या क्या मैं इसके पीछे कुछ सिद्धांत गलत समझ रहा हूं? मुझे लगता है कि जावा इस तरह की बाधा डाल सकता है। अगर यह सवाल स्पष्ट हो तो मुझे बताएं।

संपादित करें: धन्यवाद दोस्तों, प्रतिक्रियाएं मदद कर रही हैं और मुझे संदेह है कि मुझे क्या संदेह है। ऐसा प्रतीत होता है कि टाइप चेकर बिना किसी अक्षमता के किए जो मैं करना चाहता हूं उसे संभालने में सक्षम नहीं है, इसलिए मेरा सवाल यह है कि मैं वास्तव में अपरिहार्य व्यक्त करना चाहता हूं? यह हास्केल कंपाइलर के लिए है, लेकिन यह सामान्य रूप से है? यानी एक बाधा भी अस्तित्व में हो सकती है जिसका मतलब है "जांचें कि रिटर्न एन न्यूम का उदाहरण है" जो एक और उन्नत प्रकार के चेकर के लिए निर्णायक है? बस Int कर सकते हैं

{-# LANGUAGE TypeFamilies, FlexibleContexts, UndecidableInstances #-} 

class Evaluable c where 
    type Return c :: * 
    evaluate :: c -> Return c 

data Negate n = Negate n 

instance (Evaluable n, Num (Return n)) => Evaluable (Negate n) where 
    type Return (Negate n) = Return n 
    evaluate (Negate n) = negate (evaluate n) 

Return n निश्चित रूप से एक प्रकार है, जो एक वर्ग का एक उदाहरण हो सकता है:

+0

बीटीडब्ल्यू, जीएचसी ने कभी भी भाषा विस्तार की सिफारिश नहीं की, जैसे कि उदाहरण आपके परीक्षण और त्रुटि प्रक्रिया के दौरान 'फ्लेक्सिबल कॉन्टैक्स' या कुछ और? क्योंकि मुझे पूरा यकीन है कि यह किया गया - _ पर सिर्फ एक साइड-नोट है "यह हास्केल के साथ भी संभव है" _ बिट। –

उत्तर

6

असल में, आप आप वास्तव में क्या उल्लेख कर सकते हैं। आपका भ्रम एक बाधा के तर्क के बारे में हो सकता है। जवाब "सही प्रकार के साथ कुछ भी" है। Int का प्रकार * है, जैसा Return n है। Num में * -> Constraint है, इसलिए * का तर्क भी हो सकता है। Num Int को एक बाधा के रूप में लिखने के लिए यह पूरी तरह कानूनी (हालांकि खाली) है, उसी तरह Num (a :: *) कानूनी है।

+0

ठीक है, मुझे समझाया जाना चाहिए था कि मैंने पहले ही इसमें देखा है, लेकिन फ्लेक्सिबल कॉन्टैक्स और अपरिहार्य इंस्टेंस एक्सटेंशन मुझे परेशान करते हैं। मुझे लगता है कि जब तक मैं गलत नहीं हूं, तब तक वे मुझे अंत में काटने के लिए वापस आ सकते हैं। – user3773003

+4

जहां तक ​​मुझे पता है, 'फ्लेक्सिबल कॉन्टैक्स' पूरी तरह से सुरक्षित है, और बस टाइप पैरामीटर के रूप में गैर-प्रकार चर को अनुमति देता है। 'UndecidableInstances' संकलन के दौरान गैर-समाप्ति का कारण बन सकता है यदि आपके उदाहरण लूप बनाते हैं (क्योंकि संकलक इसे जांच नहीं सकता है)। अधिक जानकारी के लिए, [यह उत्तर] देखें (http://stackoverflow.com/a/5017549/925978)। – crockeea

+7

@ user3773003: मैं एरिक से कुछ मजबूत कहना चाहता हूं: मुझे नहीं लगता कि 'फ्लेक्सिबल कॉन्टैक्स' के बिना 'टाइपफमिलियों' का उपयोग करना उचित है, और संभवत: 'अनिश्चित इंस्टेंस' के बिना नहीं! गैर-लचीला संदर्भ नियम बिना किसी प्रकार के परिवार के भाषा के लिए डिजाइन किए गए थे; इसमें कोई आश्चर्य की बात नहीं है कि उन्हें विस्तार की आवश्यकता है। और चूंकि प्रकार के परिवार टाइप-स्तरीय फ़ंक्शंस हैं, इसलिए इसमें कोई आश्चर्य की बात नहीं है कि (प्रकार-स्तर) समाप्ति जांचकर्ता रास्ते में जा सकता है, खासकर जब से यह बहुत स्मार्ट नहीं है; हमारे पास मूल्य स्तर पर समाप्ति जांचकर्ता नहीं है, इसलिए 'UndecidableInstances' हमें समान रूप से अभिव्यक्त प्रकार का स्तर प्राप्त करता है। –

2

एरिक के जवाब की मदद के लिए मुझे एक संभावित विकल्प का सुझाव देने दें: एक प्रकार परिवार के बजाय एक कार्यात्मक निर्भरता का उपयोग कर:

class EvaluableFD r c | c -> r where 
    evaluate :: c -> r 

data Negate n = Negate n 

instance (EvaluableFD r n, Num r) => EvaluableFD r (Negate n) where 
    evaluate (Negate n) = negate (evaluate n) 

यह थोड़ा आसान परिणाम प्रकार के बारे में बात करने के लिए बनाता है, मुझे लगता है।उदाहरण के लिए, आप लिख सकते हैं

foo :: EvaluableFD Int a => Negate a -> Int 
foo x = evaluate x + 12 

तुम भी ConstraintKinds का उपयोग इस आंशिक रूप से लागू करने के लिए कर सकते हैं (जो कि क्यों मुझे लगता है कि अजीब दिखने क्रम में तर्क डाल):

type GivesInt = EvaluableFD Int 

आप के साथ ऐसा कर सकता है आपकी कक्षा भी, लेकिन यह अधिक परेशान होगी:

type GivesInt x = (Evaluable x, Result x ~ Int) 
+0

हां, फिर मुझे कुछ ऐसा कहना चाहिए था कि मैंने मूल प्रश्न में कोशिश की थी। इसे भी अनावश्यक संस्थानों और फ्लेक्सिबल इंस्टेंस की भी आवश्यकता है जिन्हें मैं टालना चाहूंगा। – user3773003

+0

@ user3773003, मैं बहुत आशावादी नहीं हूं कि आप इन एक्सटेंशन के बिना जो चाहते हैं उसे प्राप्त कर सकते हैं। मैं निश्चित रूप से कुछ याद कर सकता था। – dfeuer

+0

@ user3773003 सचमुच 'फ्लेक्सिबल इंस्टेंस 'और' अपरिहार्य इंस्टेंस 'के लिए कोई नकारात्मक पक्ष नहीं है, यह भी प्रभावी रूप से हानिरहित है। –

संबंधित मुद्दे