2016-05-03 6 views
7

मैं थोड़ी देर के लिए दीवार के खिलाफ अपने सिर को टक्कर लगी हूं। मेरे पास प्रकारों का एक समूह है, जो आधार प्रकार (अधिक विशेष रूप से, एक्समोनाड में लेआउट संशोधक) पर परिवर्तन का प्रतिनिधित्व करता है।क्या प्रकारों के ढेर को आसानी से समाहित करने का कोई तरीका है (f1 (f2 (f3 .... fn t))) 'as' f t a '?

लंबी कहानी छोटी, उन सभी प्रकारों में (* -> *) -> * -> * है।

मैं जो करना चाहता हूं, उन कारणों से जिनके लिए मैं वास्तव में यहां चर्चा नहीं करना चाहता हूं, इन परिवर्तनों का ढेर लेते हैं, और बेस प्रकार (जैसे * -> *) पर एक ही रूपांतरण के रूप में उनका प्रतिनिधित्व करते हैं।

मेरा पहला विचार एक प्रकार रचना ऑपरेटर

newtype ((f :: (* -> *) -> * -> *) :. (g :: (* -> *) -> * -> *)) l a 
     = Compose (f (g l) a) 

परिभाषित करने के लिए था और यह काम करता है अधिकांश भाग के लिए। लेकिन, एक मान दिया गया है, v :: f1 (f2 (f3 (... (fn l))) a कहें, v' :: (f1 :. f2 :. ... :. fn) l a प्राप्त करने के लिए मुझे Composen-1 बार लागू करना होगा, जो बहुत सुंदर और परेशान नहीं है।

तो सवाल यह है कि क्या मुझे Compose स्वचालित रूप से लागू करने का कोई तरीका है जब तक कि मुझे वह चाहिए जो मुझे चाहिए?

F.ex., अब मैं कुछ इस तरह करते हैं:

modifyLayout $ Compose . Compose . Compose . Mirror . avoidStruts . minimize . smartBorders 

मैं आपकी क्या अपेक्षाएं हैं:

modifyLayout' $ Mirror . avoidStruts . minimize . smartBorders 
    where modifyLayout' = modifyLayout . magicCompose 

इससे संबंधित एक सवाल: शायद ही व्यक्त करने के लिए एक बेहतर तरीका है अवधारणा?

प्रकार संरचना का उपयोग कर के पीछे पूरे विचार यह है:

संदर्भ के लिए, modifyLayout

modifyLayout :: (CC m Window) 
      => (forall l. (LayoutClass l Window) => l Window -> m l Window) 
      -> ConfigMonad 

स्पष्टीकरण (संपादित) है।

दो लेआउट संशोधक,

m1 :: LayoutClass l a => l a -> M1 l a 

और

m2 :: LayoutClass l a => l a -> M2 l a 

पर विचार अगर मैं इन दो रचना, मैं

m1m2 :: (LayoutClass l a, LayoutClass (M2 l) a) => l a -> M1 (M2 l) a 
m1m2 = m1 . m2 

हम यह मान सकते हैं वहाँ एक instance LayoutClass l a => LayoutClass (M2 l) a मिलता है। इसके दौरान, यह भी मान लें कि CC M1 Window और CC M2 Window के उदाहरण हैं।

अब मैं modifyLayout में इस फ़ीड ऊपर परिभाषित करने का प्रयास करें:

modifyLayout m1m2 

GHC तुरंत नेस्टेड प्रकार से उलझन में और शिकायत हो जाता है:

Couldn't match type ‘l’ with ‘M2 l’ 
    ‘l’ is a rigid type variable bound by 
     a type expected by the context: 
     LayoutClass l Window => l Window -> M1 l Window 
Expected type: l Window -> M1 l Window 
    Actual type: l Window -> M1 (M2 l) Window 

प्रकार संरचना का उपयोग करना, मुझे लगता है कि ठीक कर सकते हैं के बाद से, जीएचसी M1 :. M2mmodifyLayout हस्ताक्षर में मेल खाता है, और पूरे घोंसले भ्रम से बचाता है।समानार्थी शब्द स्पष्ट रूप से इस संपत्ति नहीं होगी।

अद्यतन:

कुछ poking बाद, मैंने पाया एक आंशिक समाधान (यकीन नहीं क्यों मैं जल्दी ही इसके बारे में नहीं सोचा था, लेकिन ओह अच्छी तरह से)

यह इस तरह एक typeclass निर्धारित करना संभव है

class S l f t | f l -> t where 
    sq :: (l a -> f a) -> (l a -> t l a) 

कार्यात्मक निर्भरता सुनिश्चित करता है कि संकलक स्वयं उदाहरण का चयन करने में सक्षम होगा।

फिर, यह संभव हो जाता है इस

instance S l (m1 l) m1 where 
    sq = id 
instance S l (m1 (m2 l)) (m1 :. m2) where 
    sq = sq . (Compose .) 
instance S l (m1 (m2 (x l))) ((m1 :. m2) :. x) where 
    sq = sq . (Compose .) 
instance S l (m1 (m2 (m3 (x l)))) (((m1 :. m2) :. m3) :. x) where 
    sq = sq . (Compose .) 
-- etc 

यह आंशिक रूप से मेरे सवाल का जवाब देता है जैसे उदाहरणों में लिखने के लिए: sq, एक परिवर्तन ढेर समाहित वहाँ एक उदाहरण घोंसले की दी गई स्तर के लिए परिभाषित प्रदान।

हालांकि, ये उदाहरण रिकर्सिव इंस्टेंस परिभाषा के लिए विनम्र प्रतीत होते हैं। अभी तक, मैं यह समझने में सक्षम नहीं था कि यह वास्तव में कैसा दिखाई देगा। तो, किसी भी अंतर्दृष्टि का स्वागत है।

+0

शायद, सुरक्षित coercions: https://wiki.haskell.org/GHC/Coercible – chi

+0

newtype वास्तव में जरूरी है

यहाँ कोड है? मैं तुरंत नहीं देखता कि कुछ प्रकार क्यों है ((f :: (* -> *) -> * -> *):। (G :: (* -> *) -> * -> *)) la = एफ (ग्लो) ए 'काम नहीं करेगा। तब आपको 'लिखें' का उपयोग करने की आवश्यकता नहीं होगी। – madidier

+0

@chi, मैंने कोशिश की। जीएचसी बहुत तेजी से प्रकार से भ्रमित हो जाता है, इसलिए इसे स्पष्ट प्रकार की टिप्पणियों की आवश्यकता होती है, जो इस उद्देश्य को हरा देता है। – lierdakil

उत्तर

2

एडम वोगट (@Aavogt) के लिए धन्यवाद, मैं अंत में एक संतोषजनक निष्कर्ष तक पहुंचने में सक्षम था।

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

instance {-# INCOHERENT #-} S l (m l) m where 
    sq = id 
instance S l ((f :. g) l') t => S l (f (g l')) t where 
    sq = squash . (Compose .) 
संबंधित मुद्दे