2012-05-16 9 views
15

मुझे एक फ़ंक्शन +++ चाहिए जो दो गणितीय वैक्टर जोड़ता है।हास्केल: एक सूची और एक ट्यूपल के बीच

मैं [x, y, z] और उपयोग के रूप में वैक्टर लागू हो सकते हैं:

(+++) :: (Num a) => [a] -> [a] -> [a] 
(+++) = zipWith (+) 

और इस तरह किसी भी n आयामी वेक्टर (तो यह [x, y] के लिए भी काम करेगा) को समायोजित।

या मैं (x, y, z) और उपयोग के रूप में वैक्टर लागू हो सकते हैं:

type Triple a = (a, a, a) 

merge :: (a -> b -> c) -> Triple a -> Triple b -> Triple c 
merge f (a, b, c) (x, y, z) = (f a x, f b y, f c z) 

(+++) :: (Num a) => Triple a -> Triple a -> Triple a 
(+++) = merge (+) 
बेशक

इस थोड़ा अधिक जटिल है, लेकिन यह जब मैं अन्य सभी वेक्टर कार्यों को लागू, कि अप्रासंगिक है (40 के बजाय 50 लाइनें)।

सूची दृष्टिकोण के साथ समस्या यह है कि मैं एक 3 डी वेक्टर के साथ 2 डी वेक्टर जोड़ सकता हूं। उस स्थिति में, zipWith बस 3 डी वेक्टर के z घटक को काट देगा। हालांकि यह समझ में आता है (अधिक संभावना है कि इसे 2 डी वेक्टर को [x, y, 0] तक विस्तारित करना चाहिए), अन्य कार्यों के लिए मुझे लगता है कि यह चुपचाप होने के लिए समस्याग्रस्त हो सकता है। ट्यूपल दृष्टिकोण के साथ समस्या यह है कि यह वेक्टर को 3 घटकों तक सीमित करता है।

सहजता से, मुझे लगता है कि यह (x, y, z) के रूप में वैक्टरों का प्रतिनिधित्व करने के लिए और अधिक समझदार होगा, क्योंकि गणितीय वेक्टर में निश्चित संख्या में घटक होते हैं और यह वास्तव में एक वेक्टर के लिए एक घटक (प्रीपेन्ड) को समझ में नहीं आता है।

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

मुझे लगता है कि मैं क्या चाहता हूं वह कार्य है जो बराबर लंबाई, या बेहतर की दो सूचियां लेता है, जो मनमानी आकार के tuples पर काम करता है।

व्यावहारिकता, मापनीयता, लालित्य इत्यादि के मामले में सुझाव सुझाव?

{-# LANGUAGE FlexibleInstances #-} -- needed to make tuples type class instances 

class Additive v where 
    (+++) :: v -> v -> v 

instance (Num a) => Additive (a,a) where 
    (x,y) +++ (ξ,υ) = (x+ξ, y+υ) 
instance (Num a) => Additive (a,a,a) where 
    (x,y,z) +++ (ξ,υ,ζ) = (x+ξ, y+υ, z+ζ) 
... 

इस तरह, चर लंबाई tuples जोड़ा जा सकता है, लेकिन यह संकलन में सुनिश्चित किया जाएगा:

+0

http: // stackoverflow।कॉम/प्रश्न/7220953/करता है-हैकेल-है-वैरैडिक-फ़ंक्शंस-टुपल्स –

+0

मुझे पता है कि यह प्रश्न थोड़ा पुराना है, लेकिन आप [वेक्टर-स्पेस] (http: //hackage.haskell) पर एक नज़र डालना चाहते हैं .org/पैकेज/वेक्टर-स्पेस) पैकेज। –

उत्तर

-1

लैंडेई और बाएंअराउंडबाउट के जवाब अच्छे हैं (आप दोनों के लिए धन्यवाद), और मुझे लगता है कि मुझे यह महसूस करना चाहिए था कि यह उतना आसान नहीं होगा जितना कि मैंने आशा की थी। सुझाए गए विकल्पों में से किसी एक को करने का प्रयास जटिल कोड के लिए करता है, जो स्वयं में कोई समस्या नहीं है, सिवाय इसके कि ऐसा लगता है कि उपयोगकर्ता कोड या तो देखने के लिए बहुत सुंदर नहीं होगा।

मुझे लगता है कि मैंने ट्यूपल्स के साथ जाने का फैसला किया है और 3-आयाम केवल वैक्टर के साथ चिपकने का फैसला किया है, क्योंकि यह सूचियों का उपयोग करने से अधिक अर्थपूर्ण रूप से सही लगता है। मैं फिर से प्रत्यारोपण कर रहा हूं map, zipWith, sum और अन्य ट्रिपल के लिए, हालांकि। मैं सादगी के साथ रहना चाहता हूं- मुझे लगता है कि अगर मुझे सूचियों के रूप में वैक्टरों के बारे में सोचने के लिए एक आकर्षक तर्क था, तो वह समाधान बेहतर काम करेगा (बशर्ते मैं सुनिश्चित करता हूं कि मैं आयामों को मिश्रित नहीं करता) ... जब मैं वास्तव में वैक्टर का उपयोग करता हूं, हालांकि, फ़ंक्शंस एक 3 डी वेक्टर को तर्क के रूप में ले जाएगा, परिवर्तनीय आयामों में से एक नहीं, और Num a => [a] इसे लागू नहीं कर सकता है।

+0

'डेटा का उपयोग करें। 'वेक्टर' पैकेज या 'एसीवीक्टर' पैकेज से वेक्टर 'जिसमें 3 डी वैक्टर हैं। इन पुस्तकालयों ने आपको समय और ऊर्जा बचाने के लिए पहले से ही सहायक कार्यों को परिभाषित किया है। – vivian

+3

लाइब्रेरी के लिए कोड जटिल हो सकता है, लेकिन आप इसे 'टाइप' परिभाषाओं और सुविधा विधियों जैसी चीज़ों का उपयोग करके उपयोगकर्ता से बहुत अच्छी तरह छुपा सकते हैं। – Landei

14

सबसे आसान तरीका है एक प्रकार कक्षा में +++ ऑपरेटर रखा, और विभिन्न टपल उदाहरणों आकार बनाने के लिए है समय-समय पर दोनों पक्षों की लंबाई समान होती है।


इस सामान्यीकरण वास्तविक प्रकार कक्षा में अपने merge की तरह एक समारोह का उपयोग करने के भी संभव है: इस मामले में, आप एक प्रकार निर्माता (सूची इकाई की तरह) के रूप में वर्ग उदाहरण निर्दिष्ट करने के लिए की जरूरत है।

class Mergable q where 
    merge :: (a->b->c) -> q a -> q b -> q c 

instance Mergable Triple where 
    merge f (x,y,z) (ξ,υ,ζ) = (f x ξ, f y υ, f z ζ) 

और फिर बस

(+++) :: (Mergable q, Num a) => q a -> q b -> q c 
+++ = merge (+) 

दुर्भाग्य से, यह नहीं करता है काफी काम है, क्योंकि प्रकार समानार्थी शब्द आंशिक रूप से मूल्यांकन नहीं किया जा सकता है।इसके बजाय आप Triple एक newtype बनाने के लिए, की तरह

newtype Triple a = Triple(a,a,a) 

जरूरत है और फिर

instance Mergable Triple where 
    merge f (Triple(x,y,z)) (Triple((ξ,υ,ζ)) = Triple(f x ξ, f y υ, f z ζ) 

निश्चित रूप से काफी के रूप में को देखने के लिए अच्छा नहीं है।

+3

@VladtheImpala: शायद आप [जापानी] पसंद करते हैं (http://codegolf.stackexchange.com/a/4824/2183)? - गंभीरता से, स्थानीय चर शब्द ग्रीक नामों को कॉल करने में क्या गलत है? यह किसी को भी अपने कोड में टाइप करने के लिए मजबूर नहीं करता है, अगर आपको यूनानी वर्णमाला पता है तो यह सहयोग करने के लिए समझ में आता है उदा। zeta के साथ z, और यदि आप मनमाने ढंग से लैटिन अक्षरों की तुलना में थोड़ा अंतर नहीं बनाते हैं। – leftaroundabout

21

आप प्रकार स्तर प्रोग्रामिंग का उपयोग कर सकते हैं। सबसे पहले हमें हर प्राकृतिक संख्या को एक अलग प्रकार बनाने की जरूरत है। प्राकृतिक संख्याओं का Peano 's परिभाषा के बाद, Z0 है, और S xx + 1

data Z = Z 
data S a = S a 

class Nat a 
instance Nat Z 
instance (Nat a) => Nat (S a) 

अब हम एक प्रकार Vec का उपयोग बस एक सूची रैप करने के लिए कर सकते हैं, लेकिन Nat का उपयोग करके अपने आकार का ट्रैक रखने के लिए है। इसके लिए हमें smart constructorsnil और <:> (ताकि आप डेटा निर्माता Vec अपने मॉड्यूल से निर्यात नहीं करना चाहिए)

data Vec a = Vec a [Int] 

nil = Vec Z [] 

infixr 5 <:> 
x <:> (Vec n xs) = Vec (S n) (x:xs) 

अब हम एक add समारोह है, जो की आवश्यकता है दो वैक्टर ही Nat है कि परिभाषित कर सकते हैं का उपयोग करें:

toList (Vec _ xs) = xs 
main = print $ toList $ add (3 <:> 4 <:> 2 <:> nil) (10 <:> 12 <:> 0 <:> nil) 
:

add :: Nat a => Vec a -> Vec a -> Vec a 
add (Vec n xs) (Vec _ ys) = Vec n (zipWith (+) xs ys) 

अब आप लंबाई जानकारी के साथ एक वेक्टर प्रकार है

बेशक यहां विभिन्न लंबाई वाले वैक्टर होने से संकलन त्रुटि हो जाएगी।

यह संस्करण को समझना आसान है, छोटे, अधिक कुशल और/या अधिक सुविधाजनक समाधान हैं।

+0

मुझे "अधिक कुशल और/या अधिक सुविधाजनक" समाधान आश्चर्य है, क्या कोई भी कुछ पॉइंटर्स देने की परवाह करता है? – sinan

+0

मुझे लगता है कि आप 'एचएलआईस्ट के साथ समान प्रभाव प्राप्त कर सकते हैं: http://hackage.haskell.org/packages/archive/HList/0.2.3/doc/html/Data-HList-HListPrelude.html – Landei

1

चूंकि ओपी अधिक हल्के दृष्टिकोण चाहता था, इसलिए मैं संबंधित प्रकारों का उपयोग करूंगा।

class VecMath a b where 
    type Res a b :: * 
    (+++) :: a -> b -> Res a b 

instance Num a => VecMath (a,a,a) (a,a,a) where 
    type Res (a,a,a) (a,a,a) = (a,a,a) 
    (x1,y1,z1) +++ (x2,y2,z2) = (x1+x2, y1+y2, z1+z2) 

instance Num a => VecMath (a,a) (a,a,a) where 
    type Res (a,a) (a,a,a) = (a,a,a) 
    (x1,y1) +++ (x2,y2,z) = (x1+x2, y1+y2, z) 

instance Num a => VecMath (a,a,a) (a,a) where 
    type Res (a,a) (a,a,a) = (a,a,a) 
    -- (+++) analog 
instance Num a => VecMath (a,a) (a,a) where 
    type Res (a,a) (a,a) = (a,a) 
    -- ... 

Res एक प्रकार समारोह, यहां अनिवार्य रूप से यह तर्क का 'बड़ा' प्रकार में जिसके परिणामस्वरूप है। लाभ यह है कि आप अभी भी सादे पुराने tuples के साथ काम कर सकते हैं, जैसे VecMath मौजूद नहीं था। अंधेरा पक्ष उदाहरणों का घातीय विस्फोट है जिसे आप लिखना चाहते हैं, यदि आप Res के डोमेन में नए प्रकार जोड़ने पर विचार करते हैं। अधिक जानकारी के लिए देखें this