मैं कुल और सुरुचिपूर्ण तरीके से निश्चित-न्यूनतम-लंबाई सूची का उपयोग कैसे कर सकता हूं?


10

मैं वर्तमान में एक फ़ंक्शन के साथ काम कर रहा हूं जो इस प्रकार है:

foo = (\(a:b:c:d:e:f:_) -> foobar a b c d e f) . (++ repeat def)

दूसरे शब्दों में, एक सूची दी गई है, यह किसी चीज़ के लिए पहले छह तत्वों का उपयोग करता है, और यदि सूची छह तत्वों से कम लंबी है, तो यह defलापता लोगों के लिए स्टैंड-इन के रूप में उपयोग करता है। यह कुल है, लेकिन इसके टुकड़े (जैसे नहीं map fromJust . filter isJust) हैं, इसलिए मुझे यह पसंद नहीं है। मैंने इसे फिर से लिखने की कोशिश की ताकि इसे किसी भी पक्षपात का उपयोग करने की आवश्यकता न हो, और यह मिल गया:

foo [] = foobar def def def def def def
foo [a] = foobar a def def def def def
foo [a,b] = foobar a b def def def def
foo [a,b,c] = foobar a b c def def def
foo [a,b,c,d] = foobar a b c d def def
foo [a,b,c,d,e] = foobar a b c d e def
foo (a:b:c:d:e:f:_) = foobar a b c d e f

मैंने तकनीकी रूप से वही किया जो मैं चाहता हूं, लेकिन अब यह एक विशाल गड़बड़ है। मैं इसे और अधिक सुरुचिपूर्ण और कम दोहरावदार तरीके से कैसे कर सकता हूं?


2
हो सकता है, uncons :: Default a => [a] -> (a,[a])जो एक चूक लिखो def। या एक चूक takeWithDef। और / या एक दृश्य पैटर्न / पैटर्न पर्यायवाची। हालांकि इसके लिए कुछ सहायक सहायक कोड लिखना पड़ता है।
ची

@ मैं सोचता हूँ कि मैं क्या करूँगा। यदि आप इसका उत्तर देते हैं, तो मैं इसे स्वीकार करूंगा।
जोसेफ सिबल-पुनः स्थापित मोनिका

2
इसके लायक क्या है, मुझे लगता है कि इसके लिए समग्रता तर्क case xs ++ repeat def of a:b:c:d:e:f:_ -> ...काफी स्थानीय है कि मैं दो बार सिर्फ इसका उपयोग करने के बारे में नहीं सोचूंगा और सभी अतिरिक्त मशीनों को छोड़ दूंगा जो मौजूदा उत्तर पेश कर रहे हैं। यह आम तौर पर अधिक वैश्विक समग्रता तर्क है (जिसमें कई फ़ंक्शन कॉल में बनाए गए इनवेरिएंट शामिल हैं, जैसे) जो मुझे परेशान करते हैं।
डैनियल वैगनर

वास्तव takeWithDefमें अगर यह एक नियमित सूची देता है, तो यह प्रयोग करने योग्य नहीं है, क्योंकि हमें मिलान करने की आवश्यकता है कि: - / उचित समाधान वह है जो डैनियल ने अपने दूसरे उत्तर में नीचे लिखा है। unconsकेवल पहला तत्व मिलता है, इसलिए यह उतना उपयोगी नहीं है।
ची

जवाबों:



6

यह कम से कम छोटा है:

foo (a:b:c:d:e:f:_) = foobar a b c d e f
foo xs = foo (xs ++ repeat def)

आप आसानी से देख सकते हैं कि पैटर्न संपूर्ण हैं, लेकिन अब आपको यह देखने के लिए थोड़ा सोचना होगा कि यह हमेशा समाप्त होता है। इसलिए मुझे नहीं पता कि क्या आप इसे सुधार मान सकते हैं।

अन्यथा हम इसे राजकीय मोनाड के साथ कर सकते हैं, हालांकि यह थोड़ा भारी है:

foo = evalState (foobar <$> pop <*> pop <*> pop <*> pop <*> pop <*> pop)
  where
    pop = do xs <- get
             case xs of [] -> pure def
                        y:ys -> put ys >> pure y

मैं भी एक अनंत धारा के प्रकार का उपयोग करके कल्पना कर सकता था

data S a = S a (S a)

क्योंकि तब आप का निर्माण कर सकता है fooसे बाहर repeat :: a -> S a, prepend :: [a] -> S a -> S a, और take6 :: S a -> (a,a,a,a,a,a), जो सभी के कुल हो सकता है। यदि आपके पास पहले से इस तरह का कोई काम नहीं है, तो शायद इसके लायक नहीं है।


3
ओह, मुझे स्ट्रीम आइडिया बहुत पसंद है। एक infix कंस्ट्रक्टर के साथ जैसे data S a = a :- S a; infixr 5 :-यह काफी साफ दिखता है; foo xs = case prepend xs (repeat def) of a:-b:-c:-d:-e:-f:-_ -> foobar a b c d e f
डैनियल वैगनर

4

बस मज़े के लिए (और अनुशंसित नहीं, यह फ़न के लिए है), यहाँ एक और तरीका है:

import Data.Default

data Cons f a = a :- f a
infixr 5 :-

data Nil a = Nil -- or use Proxy

class TakeDef f where takeDef :: Default a => [a] -> f a
instance TakeDef Nil where takeDef _ = Nil
instance TakeDef f => TakeDef (Cons f) where
    takeDef (x:xs) = x :- takeDef xs
    takeDef xs = def :- takeDef xs

foo xs = case takeDef xs of
    a:-b:-c:-d:-e:-f:-Nil -> foobar a b c d e f

पैटर्न में आप जिस प्रकार का उपयोग करते हैं, वह takeDefयह कहने के लिए एक प्रकार के स्तर को पार करने के लिए स्वाभाविक है कि कितने तत्वों को देखना है।


1
यह मेरा अब तक का पसंदीदा तरीका है। मैं शायद इसे पूरक करने के लिए एक दृश्य पैटर्न का उपयोग करूंगा। ("अनुशंसित क्यों नहीं"? क्या विपक्ष हैं?)
ची

3
जब आप टाइप-स्तरीय प्रोग्रामिंग में भारी निवेश करते हैं, तो यह वास्तव में गलत होने लगता है: एक लाइन, दस-समझ में आने वाले प्रोग्राम गुब्बारे में से कौन-सा एक प्रकार का होता है, जिससे पाठक को अपने मानसिक प्रकार-आविष्कार इंजन को गंभीरता से संलग्न करने की आवश्यकता होती है।
डैनियल वैगनर

1
में तुम्हारी बात समझ रहा हूँ। मैं foo (takeDef -> a:-b:-c:-d:-e:-f:-Nil) -> foobar a b c d e fएक पंक्ति के रूप में गिना जाता हूं । मैं बाकी की गिनती नहीं करता हूं क्योंकि यह कोड है जो कुछ पुस्तकालय में होना चाहिए, पुन: उपयोग के लिए। यदि यह केवल इस मामले के लिए लिखा जाना है, तो यह स्पष्ट रूप से ओवरकिल है जैसा कि आप कहते हैं।
ची
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.