2015-05-29 15 views
5

आप कार्यात्मक निर्भरताओं के साथ एक प्रकार के वर्ग से आश्रित प्रकार कैसे प्राप्त करते हैं और उपयोग करते हैं?आप कार्यात्मक निर्भरताओं के साथ एक प्रकार के वर्ग से आश्रित प्रकार कैसे प्राप्त करते हैं और उपयोग करते हैं?

स्पष्ट और मेरी नवीनतम प्रयास का एक उदाहरण देने के लिए (वास्तविक कोड से कम से कम मैं लिख रहा था):

class Identifiable a b | a -> b where -- if you know a, you know b 
    idOf :: a -> b 

instance Identifiable Int Int where 
    idOf a = a 

f :: Identifiable Int b => Int -> [b] -- Does ghc infer b from the functional dependency used in Identifiable, and the instance? 
f a = [5 :: Int] 

लेकिन GHC ख इसका अनुमान नहीं लगा है, ऐसा लगता है, के रूप में यह इस त्रुटि प्रिंट:

data Graph a where 
    Graph :: (Identifiable a b) => GraphImpl b -> Graph a 

getImpl :: Identifiable a b => Graph a -> GraphImpl b 
getImpl (Graph impl) = impl 

वैकल्पिक हल यहाँ जोड़ने के लिए होगा:

Couldn't match expected type ‘b’ with actual type ‘Int’ 
    ‘b’ is a rigid type variable bound by 
     the type signature for f :: Identifiable Int b => Int -> [b] 
     at src/main.hs:57:6 
Relevant bindings include 
    f :: Int -> [b] (bound at src/main.hs:58:1) 
In the expression: 5 :: Int 
In the expression: [5 :: Int] 
In an equation for ‘f’: f a = [5 :: Int] 

संदर्भ के लिए, यहाँ एक कम कम से कम उदाहरण है प्रकार आर्ग के रूप में ख ग्राफ़ बनाने के लिए:

data Graph a b | a -> b where 
    Graph :: (Identifiable a b) => GraphImpl b -> Graph a 

पूरे संदर्भ: मैं संस्थाओं प्रत्येक एक आईडी है कि एक Graph, प्रत्येक इकाई 1 नोड के लिए असाइन किया गया है। आप इकाई द्वारा एक नोड देख सकते हैं। मेरे पास Graph' भी है जिसमें नोड्स (जिसे एक इकाई असाइन की जा सकती है) शामिल है, और नोड को देखने के लिए आपको नोड की आईडी प्रदान करने की आवश्यकता है, जो एक इंट है। Graph आंतरिक रूप से Graph' का उपयोग करता है। मेरे पास IdMap है जो Graph' में नोड्स के आईडी में इकाइयों की आईडी को मानचित्र करता है।

data Graph a where 
    Graph :: (Identifiable a b) => { 
    _idMap :: IdMap b, 
    _nextVertexId :: Int, 
    _graph :: Graph' a 
} -> Graph a 

उत्तर: यह मेरा Graph परिभाषा है उपयोग प्रकार परिवारों, Daniel Wagner's answer देखते हैं। पूरी कहानी के लिए, Reid Barton's answer देखें।

+0

@Carsten धन्यवाद, 'idOf' वास्तव में काम किया सेट कर सकते हैं। बाधा के लिए, मैं यह देखने की कोशिश कर रहा था कि कक्षा के साथ एक प्रकार के 'पैटर्न मैच' के लिए हैकेल में कोई सुविधा थी या नहीं। दूसरे उदाहरण के लिए, 'ग्राफ़ ए बी' का उपयोग किये बिना इसे काम करने का कोई तरीका है ए -> बी', और/या किसी भी डिजाइन परिप्रेक्ष्य से बाद में ऐसा करने का कोई कारण है? – timdiels

उत्तर

5

यह वास्तव में थोड़ा अजीब लगता है कि जीएचसी कम से कम f के बारे में शिकायत करता है जो आपने शीर्ष पर पोस्ट किया था। लेकिन ऐसा लगता है कि टाइप परिवारों के साथ ठीक काम करता है:

{-# LANGUAGE TypeFamilies #-} 
class Identifiable a where 
    type IdOf a 
    idOf :: a -> IdOf a 

instance Identifiable Int where 
    type IdOf Int = Int 
    idOf a = a 

f :: a -> [IdOf Int] 
f _ = [5 :: Int] 

शायद आप इस विचार को अपने बड़े उदाहरण में अनुकूलित कर सकते हैं।

+0

परिवारों को टाइप करें जो मैं खोज रहा था, धन्यवाद – timdiels

7

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

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

इस के लघु संस्करण है कि कार्यात्मक निर्भरता के आसपास प्रकार चेकर के तर्क, जैसा कि आप उम्मीद कर सकते हैं के रूप में मजबूत नहीं है, खासकर GADTs की तरह नए प्रकार प्रणाली सुविधाओं के साथ संयोजन के रूप में है। मैं इसके बजाय इन परिस्थितियों में प्रकार के परिवारों का उपयोग करने की सलाह देता हूं, जैसा कि डैनियल वाग्नेर के उत्तर द्वारा उदाहरण दिया गया है।

https://ghc.haskell.org/trac/ghc/ticket/345 इसी तरह की थीम पर एक पुराना टिकट है, इसलिए आप देख सकते हैं कि यह कार्यात्मक निर्भरताओं के साथ एक लंबे समय से ज्ञात ज्ञात मुद्दा है और इसके बजाय प्रकार के परिवारों का उपयोग आधिकारिक तौर पर अनुशंसित समाधान है।

आप शैली जिसमें Identifiable दो प्रकार तर्क हैं बनाए रखना चाहते हैं, तो आप भी अपने कार्यक्रम के रूप में

type family IdOf a 
class (b ~ IdOf a) => Identifiable a b where 
    idOf :: a -> b 

type instance IdOf Int = Int 
instance Identifiable Int Int where 
    idOf a = a 

f :: Identifiable Int b => Int -> [b] 
f a = [5 :: Int] 
संबंधित मुद्दे

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