2012-06-04 15 views
19

पर एक पॉलिमॉर्फिक फ़ंक्शन कैसे लागू करें Dynamic के मान पर एक पॉलिमॉर्फिक फ़ंक्शन लागू करने का कोई सौहार्दपूर्ण तरीका है?डायनामिक मान

उदाहरण के लिए, मेरे पास Dynamic प्रकार का मान है और मैं Dynamic के अंदर मूल्य पर Just लागू करना चाहता हूं। तो यदि मूल्य toDyn True द्वारा बनाया गया था तो मैं परिणाम toDyn (Just True) होना चाहता हूं। Dynamic के अंदर होने वाले विभिन्न प्रकारों की संख्या बाध्य नहीं है।

(मैं एक समाधान जब प्रकार एक बंद ब्रह्मांड से आते हैं शामिल है, लेकिन यह अप्रिय है।)

+0

ऐसा लगता है कि 'पॉलीटाइपबल' और 'पॉलीटाइपेबल-यूटिल्स' का उपयोग इस के लिए किया जा सकता है - हालांकि आपको अभी भी सबसे खराब मामले में पूर्ण एकीकरण लागू करना होगा। – Carl

उत्तर

15

यह शायद sanest दृष्टिकोण नहीं है, लेकिन हम एक TypeRep बारे में झूठ मेरी reflection पैकेज का दुरुपयोग कर सकते हैं।

{-# LANGUAGE Rank2Types, FlexibleContexts, ScopedTypeVariables #-} 
import Data.Dynamic 
import Data.Proxy 
import Data.Reflection 
import GHC.Prim (Any) 
import Unsafe.Coerce 

newtype WithRep s a = WithRep { withRep :: a } 

instance Reifies s TypeRep => Typeable (WithRep s a) where 
    typeOf s = reflect (Proxy :: Proxy s) 

यह देखते हुए कि अब हम Dynamic तर्क के TypeRep में झांक सकते हैं और उचित रूप से हमारे Dynamic समारोह का दृष्टांत कर सकते हैं।

apD :: forall f. Typeable1 f => (forall a. a -> f a) -> Dynamic -> Dynamic 
apD f a = dynApp df a 
    where t = dynTypeRep a 
     df = reify (mkFunTy t (typeOf1 (undefined :: f()) `mkAppTy` t)) $ 
        \(_ :: Proxy s) -> toDyn (WithRep f :: WithRep s (() -> f())) 

यह बहुत आसान हो सकता है अगर base हमारे लिए apD, लेकिन यह एक रैंक 2 प्रकार की आवश्यकता है, और Typeable/Dynamic की तरह सिर्फ आपूर्ति की कुछ उन से बचने के लिए प्रबंधन, भले ही Data नहीं करता है।

एक और रास्ता सिर्फ Dynamic के कार्यान्वयन का दोहन करने के होगा:

data Dynamic = Dynamic TypeRep Any 

और unsafeCoerce अपनी खुद की Dynamic' डेटा प्रकार के लिए, आप आंतरिक में TypeRep साथ क्या करने की जरूरत नहीं है, और अपने समारोह लागू करने के बाद , unsafeCoerce सब कुछ वापस।

+2

'टाइपरप' के बारे में झूठ बोलना सरल है, इसलिए मैं इस जवाब को स्वीकार करूंगा ('असीमित कॉमर्स' का उपयोग करके 'गतिशील' के अंदर चोटी और पोक करने के लिए सिन के रूप में योग्य नहीं है)। – augustss

+0

@augustss: नैतिक अंतर कहां है? –

+1

@AndreasRossberg यह बहुत छोटा है। :) लेकिन पूर्व कुछ और मजबूत है। उदाहरण के लिए, यदि 'गतिशील' परिवर्तनों के कार्यान्वयन में 'टाइपरप' और 'कोई भी' फ़ील्ड बदलती हैं तो पूर्व में भी क्रैश होने पर पूर्व काम करेगा। – augustss