2011-01-27 26 views
19

का उपयोग किए बिना Functor कैसे बना सकता हूं?बनाना (ए, ए) एक फंक्शन

instance Functor (a, a) where 
    fmap f (x, y) = (f x, f y) 

लेकिन निश्चित है कि एक कानूनी यह व्यक्त करने के लिए तरीका नहीं है की:

Kind mis-match 
The first argument of `Functor' should have kind `* -> *', 
but `(a, a)' has kind `*' 
In the instance declaration for `Functor (a, a)' 

क्या मैं सच में चाहते हैं की तरह एक प्रकार स्तरीय समारोह है

मूल रूप से मैं इसे इस तरह काम करना चाहते हैं यह: \a -> (a, a) (अमान्य वाक्यविन्यास)। तो एक प्रकार उपनाम, शायद?

type V2 a = (a, a) 
instance Functor V2 where 
    fmap f (x, y) = (f x, f y) 

मुझे लगता है कि यह काम करेगा, लेकिन ऐसा नहीं है।

Illegal instance declaration for `Functor V2' 
(All instance types must be of the form (T t1 ... tn) 
where T is not a synonym. 
Use -XTypeSynonymInstances if you want to disable this.) 
In the instance declaration for `Functor V2' 

अगर मैं सलाह का पालन करें और TypeSynonymInstances एक्सटेंशन जोड़ने, मैं एक नया त्रुटि मिलती है:: सबसे पहले मैं इस शिकायत प्राप्त

Type synonym `V2' should have 1 argument, but has been given 0 
In the instance declaration for `Functor V2' 

खैर, ओह, कि बात है! V2 में * -> * है जो Functor उदाहरण की आवश्यकता है।

newtype V2 a = V2 (a, a) 
instance Functor V2 where 
    fmap f (V2 (x, y)) = V2 (f x, f y) 

लेकिन अब मुझे मिल गया है मेरे कोड भर V2 रों उदारतापूर्वक छिड़क करने के बजाय सिर्फ सरल tuples है, जो एक तरह से बिंदु धरा से निपटने के लिए सक्षम होने की: ठीक है, ठीक है, मैं एक newtype इस तरह उपयोग कर सकते हैं इसे Functor बनाने के लिए; उस बिंदु पर मैं अपना खुद का फ़ंक्शन vmap :: (a -> b) -> (a, a) -> (b, b) भी बना सकता हूं।

तो क्या यह अच्छी तरह से करने का कोई तरीका है, यानी newtype के बिना?

+0

आप इस तरह के एक फंक्टर को कबूल करना चाहते हैं? ऐसा लगता है कि यदि आपको विशेष मामले के ट्यूपल्स पर काम करने के लिए उबर-फ़ंक्टर शक्तियों की आवश्यकता है, तो संभवतः आपको पहले स्थान पर टुपल्स की बजाय कस्टम डेटा संरचना का उपयोग करना चाहिए। आप जिन tuples manipulating प्रतिनिधित्व कर रहे हैं क्या प्रतिनिधित्व करते हैं? –

+4

@ डैन मैं _need_ "uber-Functor शक्तियों" नहीं करता, यह केवल हल्के से सुविधाजनक होता, ऐसा लगता है कि यह संभव होना चाहिए, और यदि यह नहीं है तो मैं उत्सुक क्यों हूं। –

+0

@ पेलोटॉम मैं मानता हूं कि ऐसा लगता है कि यह संभव होना चाहिए, हालांकि ऐसा लगता है कि यह नहीं है। मैंने सोचा कि मैं अपने साबुन बॉक्स पर जाने के लिए एक पल लेगा और ट्यूपल्स को अधिभारित करने के बजाय आपकी समस्या के अनुरूप एक अभिव्यक्तित्मक संरचना बनाने की भलाई का प्रचार करूंगा। –

उत्तर

15

जैसा कि अन्य ने कहा है, नए प्रकार या डेटा घोषणाओं का उपयोग किए बिना ऐसा करने का कोई तरीका नहीं है। हालांकि, क्या आपने Control.Arrow देखा है?उन कार्यों में से कई उदाहरण के लिए, tuples के साथ बहुत उपयोगी होते हैं:

vmap :: (a -> b) -> (a,a) -> (b,b) 
vmap f = f *** f 
+0

में अच्छा विचार है, धन्यवाद! –

+1

बेहतर है 'vmap = join (***) ' – alternative

4

आप

instance Functor ((,) a) where 
    ... 

घोषणा कर सकते हैं हालांकि कि आपके जोड़ी के पहले तत्व विवश नहीं है, और fmap केवल दूसरा तत्व पर कार्रवाई होगी।

मुद्दा यह है कि एक ट्यूपल दो तत्वों के प्रकार के बीच संबंध लागू नहीं करता है।

आप आप अपने खुद के ताजा प्रकार कर सकते हैं एक newtype डेकोरेटर नहीं करना चाहते हैं:

data Pair a = P a a 

instance Functor Pair where 
    ... 

जो एक newtype एक टपल चारों ओर से साथ काम करने के आसान हो जाएगा।

+1

मैं एक मजेदार नहीं चाहता जो केवल टुपल के तत्वों में से एक पर कार्य करता है, मैं '(ए, ए)' के लिए एक मजेदार चाहता हूं, जो पहले और दूसरे तत्वों पर कार्य करता है (क्योंकि उनके पास एक ही प्रकार है) । और मैं एक नया डेटा प्रकार बनाने से बचने की कोशिश कर रहा हूं। –

+1

@ पेलोटॉम, संभव नहीं है। फ़ंक्शन एक डेटा कन्स्ट्रक्टर तर्क लेता है, '* -> *', और '(ए, ए) 'उनमें से एक नहीं है। आपको 'न्यूटाइप' या 'डेटा' का उपयोग करना होगा। – luqui

+0

@luqui मुझे लगता है कि आपको एक प्रकार का कन्स्ट्रक्टर चाहिए? यही वह है जो मुझे डर था ... लेकिन मुझे कोई कारण नहीं दिख रहा कि टाइप उपनाम क्यों काम नहीं करना चाहिए। –

0

singletons के साथ आप defunctionalized प्रतीकों के लिए एक Functor प्रकार वर्ग (Type ~> TypeType -> Type के बजाय)

{-# Language ExplicitNamespaces, TypeApplications, TypeOperators, KindSignatures, ScopedTypeVariables, DataKinds, TypeInType, TypeFamilies, AllowAmbiguousTypes, InstanceSigs #-} 

import Data.Kind (Type) 
import Data.Singletons (type (~>), Apply) 

class Functor' (f :: Type ~> Type) where 
    fmap' :: (a -> a') -> (Apply f a -> Apply f a') 

data Dup :: Type ~> Type 

type instance Dup `Apply` a = (a, a) 

instance Functor' Dup where 
    fmap' :: (a -> a') -> ((a, a) -> (a', a')) 
    fmap' f (a1, a2) = (f a1, f a2) 

यह आपको एक Prelude.Functor देता परिभाषित कर सकते हैं उदाहरण स्वचालित रूप से

newtype f $ a = App (Apply f a) 

instance Functor' f => Functor (($) f) where 
    fmap :: (a -> a') -> (f $ a -> f $ a') 
    fmap f (App fa) = App (fmap' @f f fa) 
संबंधित मुद्दे