2011-09-30 10 views
5

मैं एक बहुपदहास्केल "छद्म functor"

data Poly a = Poly [a] 

मैं fmap (take 3) polynomial की तरह कुछ करने में सक्षम होना चाहते हैं, लेकिन मैं नहीं कर सकते क्योंकि Poly नहीं वास्तव में उस f मैं उपयोग में एक functor है fmap में केवल [a] -> [b] टाइप किया जा सकता है, a -> b नहीं।

क्या कोई मुहावरे या तरीका है जो मैं व्यक्त कर सकता हूं?


संपादित करें: यहाँ एक समारोह जो करता है जो मैं चाहता है

myMap :: ([a] ->[b]) -> P a -> P b 
myMap f (P x) = P (f x) 

उपयोग:

*Main> myMap (take 3) (P [1..]) 
P [1,2,3] 

आप प्रकार sig कि यह लगभग FMAP है से देख सकते हैं, लेकिन नहीं काफी। मैं स्पष्ट रूप से myMap के लिए कोड लिखने में सक्षम हूं, लेकिन मैं सिर्फ यह जानना चाहता हूं कि इसके बजाय एक और मुहावरे का उपयोग करना चाहिए या नहीं।

+0

आप क्या चाहते हैं 'fmap (3) बहुपद' करना चाहते हैं? यह मुझे बिल्कुल समझ में नहीं आता है। - 'बहुपद' बस एक बहुपद है :: पॉली CoeffType 'बहुपद = पॉली [ए₁, ए₂ ..]'? – leftaroundabout

+0

@ बाएंअराउंडबाउट: मैंने कुछ उदाहरण कोड दिया है। – Xodarap

+0

चूंकि यह वास्तव में एक कैननिकल ऑपरेशन नहीं है (टाइपक्लास को यह कैसे पता होना चाहिए कि यह एक सूची है और उदाहरण के लिए एक ऐरे नहीं), मैं इसे बिल्कुल भी उदाहरण नहीं दूंगा। मैं इसे "कुछ-'मैप' भी नहीं कहूंगा बल्कि बल्कि 'coeffstransform' या ऐसा कुछ भी कहूंगा। – leftaroundabout

उत्तर

10

चूंकि आप गुणांक की सूची में किसी भी फ़ंक्शन को लागू करने की अनुमति देते हैं, इसलिए आपका डेटा प्रकार केवल दो उद्देश्यों को पूरा करता है।

  • आपको अतिरिक्त प्रकार की सुरक्षा मिलती है, क्योंकि Poly [a][a] से अलग है।
  • आप विभिन्न उदाहरणों को परिभाषित कर सकते हैं।

यदि आपको इनमें से किसी की भी आवश्यकता नहीं है, तो आप एक प्रकार के उपनाम का भी उपयोग कर सकते हैं।

type Poly a = [a] 

अब आप सीधे किसी भी सूची समारोह को लागू कर सकते हैं।

यदि दूसरी तरफ, आप एक विशिष्ट प्रकार चाहते हैं, तो आपको the newtype package उपयोगी मिल सकता है। उदाहरण के लिए, इस उदाहरण को दिया।

instance Newtype (Poly a) [a] where 
    pack = Poly 
    unpack (Poly x) = x 

अब आप की तरह

foo :: Poly a -> Poly a 
foo = over Poly (take 3) 

बातें लिख सकते हैं, हालांकि यह overkill हो सकता है अगर आपके myMap अपने उद्देश्यों के लिए पर्याप्त है।


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

इससे बाद में एक अलग प्रतिनिधित्व में बदलना मुश्किल हो जाता है। उदाहरण के लिए, आप की तरह

data Poly a = Poly [(a, Int)] 

जहां Int अवधि की शक्ति है एक विरल प्रतिनिधित्व करने के लिए बदलने के लिए चाहते हो सकता है। मैं सुझाव देता हूं कि आप किस परिचालन को बेनकाब करना चाहते हैं, और खुद को सीमित कर रहे हैं। उदाहरण के लिए, यह Functor उदाहरण होने का अर्थ हो सकता है जो प्रति-तत्व आधार पर काम करता है।

instance Functor Poly where 
    fmap f (Poly x) = Poly $ map f x 

अब, स्पैस प्रतिनिधित्व में परिवर्तन क्लाइंट कोड अपरिवर्तित छोड़ देता है। केवल उदाहरण (और प्रतिनिधित्व पर निर्भर अन्य कार्यों के मुट्ठी भर) को बदलना होगा।

instance Functor Poly where 
    fmap f (Poly x) = Poly $ map (first f) x 
+0

+1 महान सलाह! – luqui

+0

धन्यवाद, ऐसा लगता है कि [न्यूमेरिक प्रीलूड] (http://hackage.haskell.org/packages/archive/numeric-prelude/0.2.2.1/doc/html/src/MathObj-Polynomial.html#T) fmap का उपयोग करता है जिस तरह से आपने निर्दिष्ट किया है। – Xodarap

2

यह काम नहीं करता है, लेकिन मैंने सोचा कि यह काफी दिलचस्प वैसे भी साझा करने के लिए किया गया था:

{-#LANGUAGE GADTs #-} 

data Poly a where 
    Poly :: [b] -> Poly [b] 

अब हम एक प्रकार पाली कि a पर पैरामिट्रीकृत है है, लेकिन प्रभावी ढंग से a एक सूची हो गया है:

~% ghci Poly.hs 
GHCi, version 6.8.2: http://www.haskell.org/ghc/ :? for help 
Loading package base ... linking ... done. 
[1 of 1] Compiling Main    (Poly.hs, interpreted) 
Ok, modules loaded: Main. 
*Main> :k Poly 
Poly :: * -> * 
*Main> :t Poly 
Poly :: [b] -> Poly [b] 
*Main> case Poly [1,2,3] of _ -> 0 
0 
*Main> case Poly 4 of _ -> 0 

<interactive>:1:10: 
    No instance for (Num [b]) 
     arising from the literal `4' at <interactive>:1:10 
    Possible fix: add an instance declaration for (Num [b]) 
    In the first argument of `Poly', namely `4' 
    In the scrutinee of a case expression: Poly 4 
    In the expression: case Poly 4 of _ -> 0 
*Main> case Poly True of _ -> 0 

<interactive>:1:10: 
    Couldn't match expected type `[b]' against inferred type `Bool' 
    In the first argument of `Poly', namely `True' 
    In the scrutinee of a case expression: Poly True 
    In the expression: case Poly True of _ -> 0 

अब हम कोशिश करते हैं और इस प्रकार के लिए Functor का एक उदाहरण लिख सकते हैं:

instance Functor Poly where 
    fmap f (Poly x) = Poly (f x) 

Couldn't match expected type `[b1]' against inferred type `b2' 
    `b2' is a rigid type variable bound by 
     the type signature for `fmap' at <no location info> 
In the first argument of `Poly', namely `(f x)' 
In the expression: Poly (f x) 
In the definition of `fmap': fmap f (Poly x) = Poly (f x) 

यह काम नहीं करेगा। दिलचस्प बात यह है कि हम भी नहीं वास्तव में myMap लिख सकते हैं:

polymap f (Poly x) = Poly (f x) 

हम इस प्रयास करते हैं तो हम

GADT pattern match in non-rigid context for `Poly' 
    Tell GHC HQ if you'd like this to unify the context 
In the pattern: Poly x 
In the definition of `polymap': polymap f (Poly x) = Poly (f x) 
बेशक

मिल हम एक प्रकार टिप्पणी के साथ इसे ठीक कर सकते हैं:

polymap :: ([a] -> [b]) -> Poly [a] -> Poly [b] 

लेकिन इसके बिना, यह एक समान समस्या है जो fmap था। "मैं हमेशा सूचियों का उपयोग करने का वादा करता हूं" के इस अतिरिक्त संदर्भ के लिए फंक्टर के पास कहीं भी नहीं है, और वास्तव में यह वास्तव में नहीं हो सकता है। उदाहरण के लिए आप हमेशा undefined :: Poly Int कह सकते हैं। संक्षेप में, मुझे नहीं लगता कि वास्तव में एक मुहावरे है जो इसे व्यक्त कर सकता है (असल में, कोई शायद ऐसा करने के लिए पर्याप्त ghc एक्सटेंशन जादू के साथ आएगा)। निश्चित रूप से एक मौजूदा नहीं है।

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