मैं थोड़ी देर के लिए दीवार के खिलाफ अपने सिर को टक्कर लगी हूं। मेरे पास प्रकारों का एक समूह है, जो आधार प्रकार (अधिक विशेष रूप से, एक्समोनाड में लेआउट संशोधक) पर परिवर्तन का प्रतिनिधित्व करता है।क्या प्रकारों के ढेर को आसानी से समाहित करने का कोई तरीका है (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
प्राप्त करने के लिए मुझे Compose
n-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 :. M2
m
modifyLayout
हस्ताक्षर में मेल खाता है, और पूरे घोंसले भ्रम से बचाता है।समानार्थी शब्द स्पष्ट रूप से इस संपत्ति नहीं होगी।
अद्यतन:
कुछ 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
, एक परिवर्तन ढेर समाहित वहाँ एक उदाहरण घोंसले की दी गई स्तर के लिए परिभाषित प्रदान।
हालांकि, ये उदाहरण रिकर्सिव इंस्टेंस परिभाषा के लिए विनम्र प्रतीत होते हैं। अभी तक, मैं यह समझने में सक्षम नहीं था कि यह वास्तव में कैसा दिखाई देगा। तो, किसी भी अंतर्दृष्टि का स्वागत है।
शायद, सुरक्षित coercions: https://wiki.haskell.org/GHC/Coercible – chi
newtype वास्तव में जरूरी है
यहाँ कोड है? मैं तुरंत नहीं देखता कि कुछ प्रकार क्यों है ((f :: (* -> *) -> * -> *):। (G :: (* -> *) -> * -> *)) la = एफ (ग्लो) ए 'काम नहीं करेगा। तब आपको 'लिखें' का उपयोग करने की आवश्यकता नहीं होगी। – madidier
@chi, मैंने कोशिश की। जीएचसी बहुत तेजी से प्रकार से भ्रमित हो जाता है, इसलिए इसे स्पष्ट प्रकार की टिप्पणियों की आवश्यकता होती है, जो इस उद्देश्य को हरा देता है। – lierdakil