2015-12-17 6 views
12

के साथ फ़ंक्शन बनाएं मेरे पास हास्केल में कोई कार्य नहीं है (नहीं, यह मेरा होमवर्क नहीं है, मैं परीक्षा के लिए सीख रहा हूं)।'if' बिंदु-मुक्त

काम है:

लिखें बिंदु से मुक्त समारोह numocc जो दिया सूचियों में तत्व की घटनाओं को गिना जाता है। उदाहरण के लिए: numocc 1 [[1, 2], [2, 3, 2, 1, 1], [3]] = [1, 2, 0]

यह मेरा कोड है:

addif :: Eq a => a -> Int -> a -> Int 
addif x acc y = if x == y then acc+1 else acc 

count :: Eq a => a -> [a] -> Int 
count = flip foldl 0 . addif 

numocc :: Eq a => a -> [[a]] -> [Int] 
numocc = map . count 

numocc और count 'बिंदु से मुक्त' हैं, लेकिन वे समारोह addif जो नहीं है का उपयोग कर रहे हैं।

मुझे नहीं पता कि मैं addif बिंदु-मुक्त कार्य कैसे कर सकता हूं। if कथन बिंदु-मुक्त करने का कोई तरीका है? शायद एक चाल है जो if का उपयोग नहीं करती है?

+1

क्या आपको गणित-चेनिगन्स जैसे 'चलो fxy = 1 - छत (इंटेग्रल (xy) /Integral y से) :: Int' करने की अनुमति है? (जो आपको बिल्कुल वही नहीं है;)) – Carsten

+0

लेकिन '1 - छत (इंटग्राल (xy) से इंटग्राल (अधिकतम xy) से abs $) :: Int' अगर मुझे कुछ बुरा सीमा मामला याद नहीं आया तो शायद इसे करना चाहिए - शायद आप इसके बारे में कारण बनाना चाहते हैं या कुछ क्विक चेक चला सकते हैं;) (अच्छी तरह से मुझे कुछ नकारात्मक याद आते हैं, इसलिए आपको अधिक 'abs' करना होगा ... लेकिन सिद्धांत स्पष्ट होना चाहिए ... वास्तविक समाधान * तुच्छ * और पाठक के लिए छोड़ दिया **: डी **) – Carsten

+3

सामान्य रूप से आप 'if' कथन को फ़ंक्शन' bool :: bool -> a -> a -> a के साथ प्रतिस्थापित कर सकते हैं; बूल झूठी एफ _ = एफ; बूल ट्रू _ टी = टी', इस मामले में आप हमेशा "सामान्य" अभिव्यक्ति बना सकते हैं जिसे नियमित तरीकों से मुक्त किया जा सकता है। – user2407038

उत्तर

10

मैं इस तथ्य का प्रयोग करेंगे कि आप आसानी से परिवर्तित कर सकते हैं एक Bool एक Int का उपयोग करने के fromEnum:

addif x acc y = acc + fromEnum (x == y) 

अब आप यह बात-मुक्त बनाने के लिए हमेशा की तरह चालें लागू करने शुरू कर सकते हैं

-- Go prefix and use $ 
addif x acc y = (+) acc $ fromEnum $ (==) x y 
-- Swap $ for . when dropping the last argument 
addif x acc = (+) acc . fromEnum . (==) x 

और इसी तरह। मैं इसे मुक्त करने के सभी मजे को दूर नहीं ले जाऊंगा, खासकर जब आपके लिए यह करने के लिए उपकरण हैं।

वैकल्पिक रूप से, आप की तरह

count x = sum . map (fromEnum . (==) x) 

एक समारोह है जो लगभग मुफ्त बात लिख सकता है, और चालें है कि आप करीब हालांकि वे बहुत बुरा मिल जल्दी से, देखते हैं: मैं

count = fmap fmap fmap sum map . fmap fmap fmap fromEnum (==) 

यहाँ लगता है कि यह (.) के बजाय fmap का उपयोग करने के लिए वास्तव में अच्छा दिखता है, हालांकि आप (.) के साथ प्रतिस्थापित कर सकते हैं और यह वही कोड होगा।अनिवार्य रूप से, (fmap fmap fmap) एक साथ एक भी तर्क और एक दो तर्क समारोह तैयार करता है, अगर आप के बजाय यह नाम .: आप के रूप में

count = (sum .: map) . (fromEnum .: (==)) 

नीचे टूटी लिख सकते दे:

> :t fmap fmap fmap sum map 
Num a => (a -> b) -> [a] -> b 

तो यह एक समारोह लेता है b से a पर, b एस की एक सूची, और a पर लौटें, बहुत बुरा नहीं।

> :t fmap fmap fmap fromEnum (==) 
Eq a => a -> a -> Int 

और इस प्रकार के जो नोट करने के लिए एक महत्वपूर्ण बात है Eq a => a -> (a -> Int) के रूप में लिखा जा सकता है,। इससे इस फ़ंक्शन का रिटर्न प्रकार fmap fmap fmap sum map पर b ~ Int के साथ इनपुट से मेल खाता है, इसलिए हम उन्हें Eq a => a -> [a] -> Int प्रकार का फ़ंक्शन प्राप्त करने के लिए लिख सकते हैं।

chk :: Bool -> (a,a) -> a 
chk = ([snd,fst]!!) . fromEnum 

chk इस्तेमाल करते हुए हम addIf के एक अलग संस्करण परिभाषित कर सकते हैं:

6

एक चाल कई if functions में से एक आयात करना होगा, उदा। Data.Bool.bool 1 0 (Data.Bool.Extras में भी मिला)।

Foreign.Marshal.Utils.fromBool का उपयोग करने के लिए एक और आर्केन चाल का उपयोग किया जाएगा, जो आपको वही करता है जो आपको चाहिए। या एक ही बात, कम आर्केन: fromEnum (धन्यवाद @bheklilr)।

लेकिन मुझे लगता है कि सबसे सरल चाल केवल गिनती से बचने के लिए होगी, औरफ़ंक्शन को filter के बाद लागू करें।

+1

क्यों 'विदेशी' मार्शल 'फ़ंक्शन के बजाय' एनम 'का उपयोग न करें? यह वही काम करता है और पहले से ही 'प्रीलूड' में मौजूद है। – bheklilr

+0

@bheklilr: उह, यह नहीं पता था कि 'बूल' 'एनम' का एक उदाहरण है - आपको इसके लिए मेरा उपरांत मिल गया है :-) 'सेबूल' बस मेरे दिमाग को पार कर गया, मैंने इसे अतीत में कहीं देखा था ... – Bergi

8

क्यों नहीं

numocc x 
    = map (length . filter (== x)) 
    = map ((length .) (filter (== x))) 
    = map (((length .) . filter) (== x)) 
    = map (((length .) . filter) ((==) x)) 
    = map (((length .) . filter . (==)) x) 
    = (map . ((length .) . filter . (==))) x 
    = (map . (length .) . filter . (==)) x 

और फिर तुच्छ ईटा-संकुचन।

+1

मुझे लगता है कि यह वर्णित कार्य के लिए सबसे अधिक अनुरूप है। –

+0

@ AndrásKovács चरण-पीछे दृष्टिकोण ... :) सीएफ। [हाल ही में लिस्प एंट्री] (http://stackoverflow.com/questions/34207933/print-adjacent-duplicates-of-a-list-checheme) 'मैप हेड के कुछ जटिल समकक्षों के लिए। फ़िल्टर (not.null.drop 1)। group'। –

1

Bool के लिए Enum उदाहरण का उपयोग करना, यह है कि अगर अधिक सामान्य मामलों में इस्तेमाल किया जा सकता के लिए एक pointfree प्रतिस्थापन का निर्माण संभव है

addIf' :: Eq a => a -> a -> Int -> Int 
addIf' = curry (flip chk ((+1),id) . uncurry (==)) 

अब हम बस addIf' में chk की जगह ले सकता:

addIf :: Eq a => a -> a -> Int -> Int 
addIf = curry (flip (([snd,fst]!!) . fromEnum) ((+1),id) . uncurry (==)) 
0

मुझे लगता है कि आप Data.Bool के bool की तलाश कर रहे हैं, जो 4.7.0.0 (2014-04-08) के बाद से मौजूद है।

incif :: (Eq a, Enum counter) => a -> a -> counter -> counter 
incif = ((bool id succ) .) . (==) 

अतिरिक्त .bool को अभिव्यक्ति पार करने से पहले दो पैरामीटर लेने के लिए, == अनुमति देता है।

के बाद से मानकों के आदेश अलग है, आप incif इस तरह उपयोग करने की आवश्यकता:

(flip . incif) 

(घालमेल कि में incif पाठक के लिए एक व्यायाम के रूप में छोड़ दिया जाता है [अनुवाद:। यह तुच्छ नहीं है, और मुझे अभी तक पता नहीं है कि कैसे।;])