2010-01-11 12 views
5

मैंने numpy के array के समान फ़ंक्शन बनाया है। यह सरणियों के लिए सूचियों, 2 डी सरणियों के लिए सूचियों की सूची, आदिहास्केल प्रकार परिवार और डमी तर्क

यह इस तरह काम करता है धर्मान्तरित:

ghci> arrFromNestedLists ["hello", "world"] :: Array (Int, (Int,())) Char 
array ((0,(0,())),(1,(4,()))) [((0,(0,())),'h'),((0,(1,())),'e'),((0,(2,())),'l'),((0,(3,())),'l'),((0,(4,())),'o'),((1,(0,())),'w'),((1,(1,())),'o'),((1,(2,())),'r'),((1,(3,())),'l'),((1,(4,())),'d')] 

(Int, (Int,())) और नहीं (Int, Int) क्योंकि मैं की लंबाई बढ़ाने के लिए एक programatic रास्ते से पता नहीं है एक ट्यूपल (साइड सवाल: क्या ऐसा कोई तरीका है?)

इसकी कोडिंग अजीब थी और मुझे काम करने के लिए "वर्कअराउंड" (काम करने के लिए डमी तर्कों के आसपास गुजरना) करना पड़ा। मुझे आश्चर्य है कि क्या एक बेहतर तरीका है।

{-# LANGUAGE FlexibleInstances, ScopedTypeVariables, TypeFamilies #-} 

type family ListOfIndex i a 
type instance ListOfIndex() a = a 
type instance ListOfIndex (Int, i) a = [ListOfIndex i a] 

class Ix i => ArrConv i where 
    acBounds :: a -> ListOfIndex i a -> (i, i) 
    acFlatten :: i -> ListOfIndex i a -> [a] 

acBounds हो "चाहिए" :: ListOfIndex i a -> (i, i):

तो यहाँ कोड, बदसूरत समाधान के विवरण के साथ बाधित है। और इसी तरह acFlatten के लिए। प्रत्येक एक डमी चर (undefined हमेशा दिए गए मान है) क्योंकि अन्यथा मैं नहीं मिल सका यह संकलन करने :(

arrFromNestedLists :: forall i a. ArrConv i => ListOfIndex i a -> Array i a 
arrFromNestedLists lst = 
    listArray 
    (acBounds (undefined :: a) lst) 
    (acFlatten (undefined :: i) lst) 

ऊपर डमी undefined तर्क काम पर से गुजर रहा है दिया जाता है। यह GHC जिनमें से उदाहरण बताता है ListOfIndex उपयोग करने के लिए।

instance ArrConv() where 
    acBounds _ = const ((),()) 
    acFlatten _ = (: []) 

नीचे समारोह ArrConv का एक उदाहरण में acBounds समारोह किया गया चाहिए है, और बाहर घोषित किया जाता है सिर्फ इसलिए कि मैं ScopedTypeVariables उपयोग करने की आवश्यकता है और मैं कैसे मैं एक में कर सकते हैं पता नहीं है एक उदाहरण परिभाषा में समारोह ..

acSucBounds 
    :: forall a i. ArrConv i 
    => a -> [ListOfIndex i a] -> ((Int, i), (Int, i)) 
acSucBounds _ lst = 
    ((0, inStart), (length lst - 1, inEnd)) 
    where 
    (inStart, inEnd) = acBounds (undefined :: a) (head lst) 

instance ArrConv i => ArrConv (Int, i) where 
    acBounds = acSucBounds 
    acFlatten _ = concatMap (acFlatten (undefined :: i)) 
+3

"मुझे टुपल की लंबाई बढ़ाने के लिए प्रोग्रामेटिक तरीके से नहीं पता है।" मुझे नहीं लगता कि आप कर सकते हैं। यह एक फ़ंक्शन का एक आदर्श उदाहरण है जिसका प्रकार किसी मान पर निर्भर करता है। 'एग्डा' जैसी निर्भर रूप से टाइप की गई भाषा में करना आसान होगा, लेकिन हास्केल में असंभव है। हो सकता है कि आप कुछ आश्रित व्यवहार देने के लिए किसी भी तरह से 'जीएडीटीएस' का उपयोग कर सकें, लेकिन मेरे सिर के ऊपर से, मुझे नहीं पता कि कैसे। –

+0

हो सकता है कि टेम्पलेट हास्केल उपयोगी हो: http://www.haskell.org/bz/thdoc.htm http://www.haskell.org/haskellwiki/Template_Haskell – primodemus

+0

@primodemus: TH के साथ मैं 'ArrConv' के लिए उदाहरण बना सकता हूं 10 आयामों के सरणी के लिए, और वे इंडेक्स के लिए सामान्य टुपल्स का उपयोग करेंगे, जो एक सुधार है।लेकिन मुझे लगता है कि सीमा मनमानी है और कोड शायद बहुत कम पठनीय होने जा रहा है। – yairchu

उत्तर

4

कारण यह है कि acBounds और acFlatten करने के लिए अतिरिक्त तर्क जरूरी हैं कि प्रकार a और iListOfIndex i a -> (i, i) और ListOfIndex i a -> [a] से क्रमशः बरामद नहीं किया जा सकता है। एक वर्कअराउंड दो विधियों को एक विधि acArgs प्रकार ListOfIndex i a -> ((i, i), a) में जोड़ना है। अब एकमात्र समस्या यह है कि इसे (Int, i) के उदाहरण में उपयोग करना है जो टाइपशेकर को अपने प्रकार को सामान्यीकृत करने से रोकता है क्योंकि पहले की तरह ही समस्या होती है (उदाहरण के लिए, हम केवल fst . acArgs का उपयोग नहीं कर सकते हैं)।

 
{-# LANGUAGE TypeFamilies, FlexibleInstances #-} 

import Data.Array 

type family ListOfIndex i a 
type instance ListOfIndex() a = a 
type instance ListOfIndex (Int, i) a = [ListOfIndex i a] 

class Ix i => ArrConv i where 
    acArgs :: ListOfIndex i a -> ((i, i), [a]) 

instance ArrConv() where 
    acArgs x = (((),()), [x]) 

instance ArrConv i => ArrConv (Int, i) where 
    acArgs lst = 
    (((0, inStart), (length lst - 1, inEnd)), args >>= snd) 
    where 
     args = map acArgs lst 
     (inStart, inEnd) = fst (head args) 

arrFromNestedLists :: ArrConv i => ListOfIndex i a -> Array i a 
arrFromNestedLists = uncurry listArray . acArgs 
+0

@ रीड बार्टन: बहुत बढ़िया! धन्यवाद :) मैंने आपके उत्तर को थोड़ा सा प्रतिक्रिया दी (मुझे उम्मीद है कि आपको कोई फर्क नहीं पड़ता): 'acArgs' को पार करने के बजाय एक समारोह में इसे monomorphic बनाते हैं, अब यह केवल एक ही स्थान पर इसका उपयोग करता है। – yairchu

+0

आह, मैं देखता हूं। अच्छा लगा। –

0

आप acBounds और acFlatten अलग रखना चाहते हैं, तो आप इसे करने के लिए एक type-level tag argument जोड़ सकता है, यानी acBounds प्रकार acBounds :: Proxy a -> ListOfIndex i a -> (i, i) होगा। यह undefined तर्कों की आवश्यकता को हटा देता है, क्योंकि आप इसे (Proxy :: SomeConcreteType) पास कर सकते हैं; और acBounds के पास किसी भी उपयोगी मूल्य-स्तर की जानकारी निकालने का कोई तरीका नहीं है, क्योंकि यह इकाई प्रकार के लिए आइसोमोर्फिक (एक अनियमित तरीके से) है।

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