2012-02-17 22 views
11

मुझे लगता है अपने आप को अक्सर पैटर्न निम्नलिखित कोड लिखने:फ़ंक्शन कैसे दें [ए] -> [ए] [(ए, इंट)] पर काम करता है?

foo xs = map snd $ filter ((< 10).fst) $ zip xs [0..] 

bar ys = map snd $ sortBy (compare `on` fst) $ zip ys [0..] 

अब मैं दूर इस सार करना चाहते

foo = indexesOf (filter (<10)) 

bar = indexesOf sort 

indexesOf :: ([a] -> [a]) -> [a] -> [Int] 
indexesOf f xs = map snd $ magick $ zip xs [0..] where 
    magick = undefined 

कैसे magick प्रदर्शन करने के लिए?

+0

... मैं वास्तव में स्पष्ट नहीं कर रहा हूँ कि तुम क्या करने की कोशिश कर रहे हैं। –

+0

मेरे पास एक सूची पर काम करने वाला एक फ़ंक्शन है, 'sort' कहें। अब क्रमबद्ध सूची के बजाय मैं तत्वों के * इंडेक्स * वापस प्राप्त करना चाहता हूं। जैसे '5.0, 8.0, 7.0] के लिए 'मैं नहीं चाहता' [5.0। 7.0, 8.0] 'लेकिन' [0,2,1] '। – Landei

उत्तर

11

आपका प्रकार हस्ताक्षर काम नहीं करेगा। आपको पास किए गए फ़ंक्शन को टुपल्स की एक सूची देने में सक्षम होना चाहिए, जिसका अर्थ है कि आपको या तो उच्च-रैंक प्रकारों का उपयोग करना है ताकि इसे पॉलीमोर्फिक होने के लिए मजबूर किया जा सके, या स्पष्ट रूप से आपके प्रकार के हस्ताक्षर में टुपल्स का उल्लेख किया जा सके।

इसके बिना, आप यह देखने के लिए फ़ंक्शन को "अंदर" नहीं देख सकते हैं कि यह सूची के तत्वों को पुनर्व्यवस्थित कैसे करता है। वास्तव में, आपके प्रकार के हस्ताक्षर दिए गए पास किए गए फ़ंक्शन सूची में जो भी चाहते थे, वह कर सकते थे, जिसमें उन तत्वों को सम्मिलित करना शामिल था जो वहां से शुरू नहीं हुए थे!

{-# LANGUAGE RankNTypes #-} 

import Data.List (sortBy) 
import Data.Ord (comparing) 

indexesOf :: (forall b. (b -> a) -> [b] -> [b]) -> [a] -> [Int] 
indexesOf f xs = map snd $ f fst $ zip xs [0..] 

foo :: (Ord a, Num a) => [a] -> [Int] 
foo = indexesOf (filter . ((< 10) .)) 

bar :: Ord a => [a] -> [Int] 
bar = indexesOf (sortBy . comparing) 

ध्यान दें कि मैं भी पारित कर दिया समारोह के लिए एक अतिरिक्त तर्क जोड़ने के लिए किया था यह बताने के लिए भाग से की परवाह करता है निकालने के लिए करने के लिए:

यहाँ मैं क्या उच्च रैंक प्रकार का उपयोग कर काम करने के लिए मिल गया है जिस सूची में यह काम कर रहा है उसके तत्व। इसके बिना, आप केवल उन कार्यों का उपयोग करने में सक्षम होंगे जो सूची के तत्वों का निरीक्षण नहीं करते हैं, जैसे कि reverse, और यह बहुत उपयोगी नहीं होगा।

उदाहरण GHCi में चलाएँ:

> let xs = [42, 0, 7, 3, 12, 17, 99, 36, 8] 
> foo xs 
[1,2,3,8] 
> bar xs 
[1,3,2,8,4,5,7,0,6] 
> indexesOf (const reverse) xs 
[8,7,6,5,4,3,2,1,0] 
+0

मुझे लगता है कि आप शीर्षक में प्रश्न का उत्तर दे रहे हैं। –

+0

(जारी) ... लेकिन दिए गए उदाहरणों में फ़ंक्शन वास्तव में ':: (Ord a) => [a] -> [a]' है। तो आप "अंदर देखो" कर सकते हैं। –

+0

@ राफेल कैएटानो: आपको अभी भी एक उच्च रैंक प्रकार के माध्यम से या टाइप हस्ताक्षर में स्पष्ट रूप से tuples का उल्लेख करके एक अलग 'ए' चुनने में सक्षम होना चाहिए। आप _could_ टाइप हस्ताक्षर 'इंडेक्सऑफ :: (फोरल बी। ऑर्ड बी => [बी] -> [बी]) -> [ए] -> [इंट]', हालांकि यह केवल 'सॉर्ट' उदाहरण के लिए काम करेगा , और 'फ़िल्टर' वाला नहीं, क्योंकि फ़ंक्शन केवल एक दूसरे के साथ तत्वों की तुलना करने में सक्षम होगा। यह '10' के खिलाफ तुलना करने में सक्षम नहीं होगा। – hammar

4

महान सवाल है, लेकिन मुझे लगता है कि ऐसी कोई समारोह वहाँ मौजूद है। Theorems For Free! देखें। हथौड़ा की तरह कहते हैं, आपको उन कार्यों को पारित करने की आवश्यकता है जो स्पष्ट रूप से tuples लेते हैं।

यहाँ

मेरी थोड़ा सरलीकृत संस्करण है कि RankNTypes की आवश्यकता नहीं है (जो, बेशक, नहीं एक मूल कोड पर बहुत अच्छा सुधार) है:

import Data.List 
import Data.Ord 

indexesOf :: ([(a,Int)] -> [(a,Int)]) -> [a] -> [Int] 
indexesOf f xs = map snd $ f $ zip xs [0..] 

foo :: (Ord a,Num a) => [a] -> [Int] 
foo = indexesOf $ filter $ (< 10) . fst 

bar :: Ord a => [a] -> [Int] 
bar = indexesOf $ sortBy $ comparing fst 
+1

यह सही है, हालांकि उच्च-रैंक प्रकार आपको थोड़ा मजबूत गारंटी देते हैं क्योंकि फ़ंक्शन पूर्णांक के साथ गड़बड़ नहीं कर सकता है। यह सब कुछ कर सकते हैं सूची में मौजूदा आइटम को पुन: व्यवस्थित, प्रतिलिपि बनाएँ और हटा दें। – hammar

+0

यह सच है। साथ ही, जब किसी के पास एक प्रकार का कार्य होता है -> Int, यह छोटा होना चाहिए, यानी स्थिर (या अपरिभाषित) होना चाहिए। – mnish

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