गैर-एफपी लोगों द्वारा कार्यात्मक प्रोग्रामिंग की थोड़ी मात्रा को समझा जा सकता है? [बन्द है]


43

केस : मैं एक कंपनी में काम कर रहा हूं, पायथन में एक एप्लिकेशन लिख रहा हूं जो सरणियों में बहुत सारे डेटा को संभाल रहा है। मैं इस समय इस कार्यक्रम का एकमात्र डेवलपर हूं, लेकिन यह शायद भविष्य में (1-3 वर्ष) किसी अन्य प्रोग्रामर द्वारा मेरे लिए अज्ञात इस समय उपयोग / संशोधित / विस्तारित किया जाएगा। मैं शायद तब सीधे मदद करने के लिए नहीं रहूंगा, लेकिन हो सकता है कि ईमेल के माध्यम से कुछ सहायता दे अगर मेरे पास इसके लिए समय है।

इसलिए, एक डेवलपर के रूप में जिसने कार्यात्मक प्रोग्रामिंग (हास्केल) सीखा है, मैं उदाहरण के लिए, इस तरह से फ़िल्टर करना हल करता हूं:

filtered = filter(lambda item: included(item.time, dur), measures)

बाकी कोड OO है, यह केवल कुछ छोटे मामले हैं जहां मैं इसे इस तरह हल करना चाहता हूं, क्योंकि यह मेरे अनुसार बहुत सरल और अधिक सुंदर है।

प्रश्न : क्या इस तरह कोड लिखना आज ठीक है?

  • कैसे एक डेवलपर जो लिखित / सीखे नहीं है एफपी इस तरह कोड पर प्रतिक्रिया करता है?
  • क्या यह पठनीय है?
  • परिवर्तनीय?
  • क्या मुझे एक बच्चे को समझाते हुए दस्तावेज लिखना चाहिए कि रेखा क्या करती है?

     # Filter out the items from measures for which included(item.time, dur) != True

मैंने अपने मालिक से पूछा है, और वह बस कहता है "एफपी काला जादू है, लेकिन अगर यह काम करता है और सबसे कुशल समाधान है, तो इसका उपयोग करना ठीक है।"

इस पर आपकी क्या राय है? एक गैर-एफपी प्रोग्रामर के रूप में, आप कोड पर कैसे प्रतिक्रिया करते हैं? क्या कोड "googable" है ताकि आप समझ सकें कि यह क्या करता है? मुझे इस पर प्रतिक्रिया पसंद आएगी।


14
मेरी राय में कई आधुनिक भाषाएं कुछ हद तक कार्यात्मक प्रोग्रामिंग की अनुमति देती हैं और इसका उपयोग करना अधिक से अधिक सामान्य हो जाता है। व्यक्तिगत रूप से मैं कहूंगा कि यह कम से कम (अपेक्षाकृत सरल फ़िल्टरिंग / मैपिंग कार्यों के लिए) है।
जोआचिम सॉर

मैं आपको एक अप्रभावित उत्तर नहीं दे सकता, क्योंकि मुझे एफपी पसंद है। एक टिप्पणी जोड़ना अच्छा होगा, अगर यह सरल से परे है।
ब्रूनो स्कैपर

3
आपकी टिप्पणी स्पष्ट हो सकती है; फ़िल्टर में ऐसे तत्व शामिल हैं जिनके लिए परीक्षण सत्य है, इसलिए आपकी टिप्पणी पढ़ी जा सकती है: # Select the item's from measures for which included(item.time, dur) == Trueदोहरा नकारात्मक से बचने से हमेशा समझ में सुधार होता है।
Martijn Pieters

6
क्या आपने इसके बजाय सूची समझ का उपयोग करने पर विचार किया है? उन्हें अक्सर मानचित्र / फ़िल्टर की तुलना में अधिक "पायथोनिक" माना जाता है।
प्रेत ० मी।

2
@ मटज़ामुहिक, यह सुंदर है ...;)
kd35a

जवाबों:


50

क्या यह पठनीय है?

मेरे लिए: हाँ, लेकिन मैं समझने के लिए आए हैं, कि अजगर समुदाय अक्सर सूची comprehensions का उपयोग करने से एक क्लीनर समाधान पर विचार करने लगता है map()/ filter()

वास्तव में, जीवीआर ने उन कार्यों को पूरी तरह से छोड़ने पर भी विचार किया

इस पर विचार करो:

filtered = [item for item in measures if included(item.time, dur)]

इसके अलावा, यह लाभ है कि एक सूची समझ हमेशा एक सूची वापस कर देगा। map()और filter()दूसरी ओर पायथन 3 में एक पुनरावृत्तिकर्ता को लौटाएगा।

नोट: यदि आप के बजाय एक इटरेटर करना चाहते हैं, यह जगह के रूप में सरल रूप में है []के साथ ():

filtered = (item for item in measures if included(item.time, dur))

ईमानदारी से कहूं तो मैं प्रयोग करने के लिए कोई कारण नहीं करने के लिए कम देखने map()या filter()अजगर में।

क्या यह परिवर्तन योग्य है?

हां, निश्चित रूप से, हालांकि, उस आसान को बनाने के लिए एक चीज है: इसे एक फ़ंक्शन बनाएं, लैम्बडा नहीं।

def is_included(item):
    return included(item.time, dur)
filtered = filter(is_included, measures)
filtered = [item for item in measures if is_included(item)]

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

एक डेवलपर जो इस तरह से कोड पर एफपी प्रतिक्रिया नहीं लिखता / सीखता है, वह कैसे करता है?

वह पाइथन डॉक्यूमेंटेशन के लिए जाता है और जानता है कि यह पांच मिनट बाद कैसे काम करता है। अन्यथा, उसे पायथन में प्रोग्रामिंग नहीं करनी चाहिए।

map()और filter()कर रहे हैं अत्यंत सरल। ऐसा नहीं है कि आप उन्हें भिक्षुओं को समझने के लिए कह रहे हैं। इसलिए मुझे नहीं लगता कि आपको ऐसी टिप्पणियाँ लिखने की आवश्यकता है। अच्छे चर और फ़ंक्शन नामों का उपयोग करें, फिर कोड लगभग आत्म व्याख्यात्मक है। आप अनुमान नहीं लगा सकते कि कौन सी भाषा एक डेवलपर को बताती है। आप सभी जानते हैं, अगले डेवलपर को यह नहीं पता होगा कि एक शब्दकोश क्या है।

हम जो नहीं समझते हैं वह आमतौर पर हमारे लिए पठनीय नहीं होता है। इस प्रकार, आप तर्क कर सकते हैं कि यह सूची समझ से कम पठनीय नहीं है यदि आपने पहले कभी भी दोनों को नहीं देखा है। लेकिन जैसा कि जोशुआ ने अपनी टिप्पणी में उल्लेख किया है, मेरा भी मानना ​​है कि अन्य डेवलपर्स जो उपयोग करते हैं, उसके अनुरूप होना महत्वपूर्ण है - कम से कम यदि विकल्प कोई पर्याप्त लाभ नहीं प्रदान करता है।


5
यह जनरेटर के भावों का भी उल्लेख करने योग्य हो सकता है , जो सूची समझ के समान काम करते हैं, लेकिन सूचियों के बजाय जनरेटर लौटाते हैं, जैसा कि अजगर में 3. mapऔर filterकरते हैं
जेम्स

@ नाम: महान विचार, मैंने उन्हें अपनी पोस्ट में जोड़ा है। धन्यवाद!
प्रेत ० मी।

2
मैं आमतौर पर reduceएक प्रति-उदाहरण के रूप में आपके सामने लाता हूं , आप हमेशा एक सूची समझने वाले तर्क का उपयोग कर सकते हैं , क्योंकि reduceइनलाइन जनरेटर या सूची समझ के साथ बदलना अपेक्षाकृत कठिन है ।
कोजिरो

4
प्रश्न में भाषा के पसंदीदा मुहावरे को नोट करने के लिए +1। IMHO संगतता का जबरदस्त मूल्य है और भाषा का उपयोग इस तरीके से किया जाता है कि "वक्ताओं" का एक महत्वपूर्ण हिस्सा कई बार टिप्पणियों की तुलना में अधिक स्थिरता प्रदान कर सकता है।
जोशुआ ड्रेक

4
+1 के लिए "वह पाइथन डॉक्यूमेंटेशन के लिए जाता है और जानता है कि यह पाँच मिनट बाद कैसे काम करता है। नहीं तो, उसे पियोन में प्रोग्रामिंग नहीं करनी चाहिए।"
बजरके फ्रायंड-हैन्सन

25

चूंकि डेवलपर समुदाय कार्यात्मक प्रोग्रामिंग में रुचि ले रहा है, इसलिए भाषाओं में कुछ कार्यात्मक प्रोग्रामिंग को देखना असामान्य नहीं है जो मूल रूप से पूरी तरह से वस्तु उन्मुख थे। एक अच्छा उदाहरण C # है, जहां गुमनाम प्रकार और लंबोदर अभिव्यक्ति कार्यात्मक प्रोग्रामिंग के माध्यम से बहुत कम और अभिव्यंजक होने में सक्षम हैं।

यह कहा जा रहा है, कार्यात्मक प्रोग्रामिंग शुरुआती लोगों के लिए अजीब है। उदाहरण के लिए, जब एक प्रशिक्षण पाठ्यक्रम के दौरान, मैंने शुरुआती लोगों को समझाया कि वे C # में कार्यात्मक प्रोग्रामिंग के माध्यम से अपने कोड को कैसे बढ़ा सकते हैं, उनमें से कुछ आश्वस्त नहीं थे, और कुछ ने कहा कि मूल कोड उनके लिए समझना आसान था। मैंने उन्हें जो उदाहरण दिया वह निम्नलिखित था:

रिफैक्टरिंग से पहले कोड:

var categorizedProducts = new Dictionary<string, List<Product>>();

// Get only enabled products, filtering the disabled ones, and group them by categories.
foreach (var product in this.Data.Products)
{
    if (product.IsEnabled)
    {
        if (!categorizedProducts.ContainsKey(product.Category))
        {
            // The category is missing. Create one.
            categorizedProducts.Add(product.Category, new List<Product>());
        }

        categorizedProducts[product.Category].Add(product);
    }
}

// Walk through the categories.
foreach (var productsInCategory in categorizedProducts)
{
    var minimumPrice = double.MaxValue;
    var maximumPrice = double.MinValue;

    // Walk through the products in a category to search for the maximum and minimum prices.
    foreach (var product in productsInCategory.Value)
    {
        if (product.Price < minimumPrice)
        {
            minimumPrice = product.Price;
        }

        if (product.Price > maximumPrice)
        {
            maximumPrice = product.Price;
        }
    }

    yield return new PricesPerCategory(category: productsInCategory.Key, minimum: minimumPrice, maximum: maximumPrice);
}

एफपी का उपयोग करके रिफैक्टिंग के बाद समान कोड:

return this.Data.Products
    .Where(product => product.IsEnabled)
    .GroupBy(product => product.Category)
    .Select(productsInCategory => new PricesPerCategory(
              category: productsInCategory.Key, 
              minimum:  productsInCategory.Value.Min(product => product.Price), 
              maximum:  productsInCategory.Value.Max(product => product.Price))
    );

इससे मुझे लगता है कि:

  • यदि आप जानते हैं कि आपको चिंता नहीं होनी चाहिए, तो अगले डेवलपर जो आपके कोड को बनाए रखेंगे, उनके पास समग्र अनुभव और कार्यात्मक प्रोग्रामिंग के कुछ ज्ञान होंगे, लेकिन:

  • अन्यथा, या तो कार्यात्मक प्रोग्रामिंग से बचें, या एक गैर-कार्यात्मक प्रोग्रामिंग बनाम आपके दृष्टिकोण के सिंटैक्स, फायदे और संभावित कैविटीज़ को एक ही समय में बताते हुए एक मौखिक टिप्पणी करें।


8
+1 यदि एफपी आपके कोड को किसी के लिए अधिक पठनीय नहीं बनाता है , तो आप इसे गलत कर रहे हैं।
ग्योर्गी एन्द्रसेक

7
मैं देख सकता हूं कि पूर्व में स्निपेट को पहले से अधिक पठनीय माना जा सकता है। लेकिन क्या होगा अगर हम इसे 100 से गुणा करें? लगभग अंग्रेजी की तरह का वर्णन वाक्य 100 लघु संक्षिप्त पढ़ना क्या पाइपलाइन की तर्ज के हजारों बनाम कैसे कोड। कोड की सरासर मात्रा, चाहे कितनी ही परिचित क्यों न हो, इतनी भारी होनी चाहिए कि परिचित अब इतनी बड़ी जीत नहीं है। कुछ बिंदु पर किसी के लिए भी पहले एफपी के तत्वों के साथ सहज होना आसान है और फिर परिचित कोड की हजारों पंक्तियों को पढ़ना बनाम मुट्ठी भर लाइनों को पढ़ना है।
एसाइलिजा

7
जो मुझे सबसे ज्यादा परेशान करता है, वह यह है कि हम विश्वास करते हैं कि यह डेवलपर्स के लिए स्वीकार्य है कि वह कार्यात्मक शैली न सीखे। फायदे कई बार साबित हुए हैं, प्रतिमान मुख्यधारा की भाषाओं द्वारा समर्थित है। यदि लोगों को कार्यात्मक तकनीकों को समझने की क्षमता की कमी है, तो उन्हें सिखाया जाना चाहिए या खुद को सिखाना चाहिए, भले ही वे इसका उपयोग करने का इरादा न करें। मैं एक जलते हुए जुनून के साथ XSLT से नफरत करता हूं, लेकिन इसने मुझे इसे एक पेशेवर के रूप में सीखने से नहीं रोका है।
Sprague

2
@ मेनमा आपकी बात पूरी तरह से मान्य है, मुझे और अधिक विशिष्ट होना चाहिए था। मेरा मतलब है कि किसी भी भाषा में एक डेवलपर से उन भाषाओं की सुविधाओं का प्रभावी ढंग से उपयोग करने की उम्मीद की जानी चाहिए। उदाहरण के लिए, C # में 'फंक्शनल स्टाइल' का उपयोग करना (फ़िल्टर / मैप / स्टाइल प्रोग्रामिंग कम करना, या पासिंग फ़ंक्शंस का उपयोग करना) कोई नई बात नहीं है, और इसलिए मुझे लगता है कि कोई भी सी # डेवलपर्स जो इस तरह के स्टेटमेंट को पढ़ने में सक्षम नहीं हैं, उन्हें अपडेट करना चाहिए कौशल ... शायद बहुत जल्दी। मुझे निश्चित रूप से लगता है कि प्रत्येक डेवलपर को थोड़ा हास्केल सीखना चाहिए, लेकिन केवल शैक्षणिक कारणों से। यह अलग बात है।
Sprague

2
@Sprague: मैं आपकी बात मानता हूँ और इससे सहमत हूँ। यह सिर्फ इतना है कि हम उदाहरण के लिए सी # प्रोग्रामर से एफपी से प्रतिमानों का उपयोग शुरू करने के लिए शायद ही उम्मीद कर सकते हैं, जब उन प्रोग्रामर में से कई भी जेनरिक का उपयोग नहीं करते हैं। जब तक बहुत सारे अकुशल प्रोग्रामर नहीं होते हैं, तब तक हमारे पेशे पर पट्टी कम होगी, खासकर जब तक कि तकनीकी पृष्ठभूमि वाले अधिकांश व्यक्ति यह नहीं समझते हैं कि विकास क्या है।
आर्सेनी मूरज़ेंको

20

मैं एक गैर-एफपी प्रोग्रामर हूं और हाल ही में मुझे अपने सहयोगी के कोड को जावास्क्रिप्ट में संशोधित करना था। कॉलबैक के साथ एक Http-request थी जो आपके द्वारा शामिल किए गए विवरण की तरह दिखती थी। मुझे यह कहना होगा कि मुझे यह सब पता लगाने में कुछ समय (जैसे आधा घंटा) लगा (सभी में कोड बहुत बड़ा नहीं था)।

कोई टिप्पणी नहीं थी, और मुझे लगता है कि किसी के लिए कोई आवश्यकता नहीं थी। मैंने अपने सहकर्मी से उनके कोड को समझने में मेरी मदद करने के लिए भी नहीं कहा।

इस बात को ध्यान में रखते हुए कि मैं लगभग 1.5 वर्षों से काम कर रहा हूं, मुझे लगता है कि अधिकांश प्रोग्रामर ऐसे कोड को समझने और संशोधित करने में सक्षम होंगे, जब से मैंने किया था।

इसके अलावा, जैसा कि जोआचिम साउर ने अपनी टिप्पणी में कहा, अक्सर कई भाषाओं में एफपी के टुकड़े होते हैं, जैसे सी # (इंडेक्सऑफ, उदाहरण के लिए)। इतने गैर-एफपी प्रोग्रामर इससे बहुत बार निपटते हैं, और आपके द्वारा शामिल कोड स्निपेट कुछ भयानक या समझ से बाहर नहीं है।


1
आपके कमेंट के लिए धन्यवाद! इसने मुझे अन्य परिप्रेक्ष्य में अधिक जानकारी दी। घर-अंधा बनना आसान है, और फिर आप यह नहीं जानते कि जब आप FP :) को नहीं जानते थे तो यह कैसा दिखता था
kd35a

1
@ kd35a, आपका स्वागत है। सौभाग्य से, मैं यहां उद्देश्यपूर्ण हो सकता हूं))
सुपर जूल

1
+1 इंगित करने के लिए कि कई भाषाओं में अब एफपी के तत्व हैं।
जोशुआ ड्रेक


3

मैं निश्चित रूप से हाँ कहूँगा!

कार्यात्मक प्रोग्रामिंग के कई पहलू हैं, और उच्च-क्रम के कार्यों का उपयोग करना, जैसा कि आपके उदाहरण में, उनमें से केवल एक है।

उदाहरण के लिए, मैं किसी भी भाषा में लिखे गए किसी भी सॉफ्टवेयर के लिए शुद्ध कार्यों को लिखना बेहद महत्वपूर्ण मानता हूं (जहां "शुद्ध" से मेरा कोई मतलब नहीं है), क्योंकि:

  • वे इकाई परीक्षण के लिए आसान कर रहे हैं
  • वे साइड-इफ़ेक्टिंग फ़ंक्शंस की तुलना में बहुत अधिक कंपोज़ेबल हैं
  • वे डिबग करना आसान है

मैं अक्सर मूल्यों और चर को बदलने से बचता हूं - एफपी से उधार ली गई एक और अवधारणा।

ये दोनों तकनीकें पायथन और अन्य भाषाओं में ठीक काम करती हैं जिन्हें आमतौर पर कार्यात्मक के रूप में वर्गीकृत नहीं किया गया है। वे अक्सर भाषा (यानी finalजावा में चर) द्वारा समर्थित हैं । इस प्रकार, भविष्य के रखरखाव प्रोग्रामर कोड को समझने के लिए एक विनम्र बाधा का सामना नहीं करेंगे।


2

पिछले साल मैंने जिस कंपनी में काम किया था, उसी पर हमारी यही चर्चा थी।

चर्चा "जादुई कोड" से संबंधित है और अगर इसे प्रोत्साहित किया जाना था या नहीं। जब इसे थोड़ा और अधिक देखा गया तो ऐसा लगा कि लोग वास्तव में "जादुई कोड" पर बहुत अलग विचार रखते थे। जिन लोगों ने चर्चा को लाया, उनमें से ज्यादातर का मतलब यह था कि अभिव्यक्ति (PHP में) जो कार्यात्मक-शैली का उपयोग करता था "जादुई कोड" था, जबकि डेवलपर्स जो अन्य भाषाओं से उत्पन्न हुए थे, जिन्होंने अपने कोड में अधिक FP शैली का उपयोग किया था, ऐसा लगता है कि जादुई कोड बल्कि था जब आपने फ़ाइल नाम और इसके माध्यम से फ़ाइलों का गतिशील समावेश किया।

हम इस पर कभी भी अच्छे निष्कर्ष पर नहीं आए, इससे अधिक लोग ज्यादातर कोड सोचते हैं जो अपरिचित दिखता है "जादुई" या पढ़ने के लिए कठिन है। तो क्या यह कोड से बचने के लिए एक अच्छा विचार है जो अन्य उपयोगकर्ताओं के लिए अपरिचित लगता है? मुझे लगता है कि यह इस बात पर निर्भर करता है कि इसका उपयोग कहां किया जाता है। मैं एक मुख्य विधि (या अनुप्रयोगों के महत्वपूर्ण केंद्रीय भागों) में एफपी-शैली के भावों (डायनेमिक फ़ाइल समावेशन और इतने पर) का उपयोग करने से बचना चाहिए जहां डेटा को एक स्पष्ट और आसान-से-पढ़ने, सहज ज्ञान युक्त तरीके से सुरंग में होना चाहिए। दूसरी ओर, मुझे नहीं लगता कि किसी को लिफाफे को धकेलने से डरना चाहिए, अन्य डेवलपर्स शायद एफपी को जल्दी से सीखेंगे यदि उन्हें एफपी कोड का सामना करना पड़ता है और शायद मुद्दों पर परामर्श करने के लिए कुछ अच्छे इन-हाउस संसाधन हैं।

टीएल; डीआर: अनुप्रयोगों के उच्च स्तरीय केंद्रीय भाग (जिसे एप्लिकेशन की कार्यक्षमता के अवलोकन के लिए पढ़ने की आवश्यकता है) से बचें। अन्यथा इसका उपयोग करें।


उच्च स्तर के कोड में इसका उपयोग करने से बचें!
kd35a

मैंने हमेशा सोचा है कि औपचारिकता की कमी है, और बहुत अधिक अवसर, विभिन्न प्रकार के ब्लॉकों में प्रोग्रामिंग की तकनीकों को परिभाषित करने में (जैसे कि स्थिर तरीके, सार्वजनिक तरीके, निर्माता, आदि) अच्छा जवाब ... यह मुझे कुछ फिर से बना रहा है। उन विचारों के।
Sprague

2

C ++ समुदाय को हाल ही में लैम्बडा के रूप में अच्छी तरह से मिला है, और मुझे विश्वास है कि उनके पास लगभग एक ही सवाल है। उत्तर भले ही एक जैसा न हो। C ++ समतुल्य होगा:

std::copy_if(measures.begin(), measures.end(), inserter(filter),
  [dur](Item i) { return included(i, dur) } );

अब std::copyनया नहीं है, और _ifवेरिएंट भी नए नहीं हैं, लेकिन लैम्ब्डा है। फिर भी इसे स्पष्ट रूप से संदर्भ में स्पष्ट रूप से परिभाषित किया गया है: durकब्जा कर लिया है और इसलिए निरंतर है, Item iलूप में भिन्न होता है, और एकल returnकथन सभी काम करता है।

यह कई सी ++ डेवलपर्स के लिए स्वीकार्य लगता है। मैंने उच्च-आदेश वाले लंबोदर पर राय नहीं ली है, हालांकि, और मुझे बहुत कम स्वीकृति की उम्मीद है।


दिलचस्प बात यह है कि, यह किस भाषा में है, इसके आधार पर अलग-अलग उत्तर हो सकते हैं। संभवतः @Christopher Käck से संबंधित है कि कैसे PHP-कोडर्स को इस तरह के सामान की अजगर-कोडर्स की तुलना में अधिक समस्या थी।
kd35a

0

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

यदि हाँ, तो आप शायद जाने के लिए अच्छे हैं। यदि नहीं, तो आपको इसे स्पष्ट करना चाहिए।

क्या आपका सहकर्मी कुछ गलत हो सकता है और कुछ ऐसा नहीं समझ सकता जो स्पष्ट होना चाहिए? हाँ, लेकिन आप हमेशा KISS के अनुसार कार्यक्रम चाहिए।

हो सकता है कि आपका कोड अधिक कुशल / अच्छा दिखने वाला / अधिक सीधा, बेवकूफ-सबूत दृष्टिकोण से सुरुचिपूर्ण हो? फिर आपको खुद से पूछने की ज़रूरत है: क्या मुझे ऐसा करने की ज़रूरत है? फिर, अगर जवाब नहीं है, तो ऐसा मत करो!

अगर इस सब के बाद भी, आपको लगता है कि आपको जरूरत है और इसे एफपी तरीके से करना चाहते हैं, तो हर तरह से इसे करें। अपनी प्रवृत्ति पर भरोसा करें, वे किसी भी मंच पर अधिकांश लोगों की तुलना में आपकी आवश्यकताओं के लिए बेहतर हैं :)


डाउनवोट का कारण स्पष्ट करने के लिए स्वतंत्र महसूस करें
अर्नब दत्ता
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.